Structures are a very useful means of organizing data in your ColdFusion programs. But, they’re often misunderstood, overlooked, or not used to the full — even by the most skilled ColdFusion coders.
In this article, we’ll take a look at what structures are, and how you can use them. We’ll also look at some of the most common structures that many people overlook on a regular basis.
What is a Struct?
First of all, what is a structure (or “struct’, as it’s known in ColdFusion)? A struct is a means of storing data. If you’ve done any programming in Java, you might liken it to a HashMap. It’s also similar to a hash in Perl. We can store a series of related data in a struct. Every piece of data has a name and a value, and we can retrieve a particular value by calling the struct and passing it the name of the value we want. Think of this process as being similar to storing several variables with different names inside one variable.
Let’s start with an example. Imagine we’re building an online book store and we want to store information about a single book in one data structure. Now, normally, we would probably store our data in a database, and use a query to access and display it. But, for this example, we’re going to use structs. Every book is going to have a title, an author, a description, a publish year, and an ISBN number. We’ll start by creating a struct to hold this data.
<cfset myBook = StructNew()>
Here, we create a variable called
myBook, and we tell ColdFusion that this is going to be a structure. If we don’t explicitly tell ColdFusion that this will be a structure, it won’t work correctly. Now, let’s add our data to the struct:
<cfset a = StructInsert(myBook, \"title\", \"All About ColdFusion\", 1)>
Let’s stop and talk about this
StructInsert function before we move on. The first parameter of the function is the name of the struct to which we want to add a key. The next parameter is the name of the key we want to add. For this parameter, you can use a variable or a string literal (as we’ve done here). The next parameter is the value for the key. Just as with the name of the key, we can use a variable or a string literal in this case. The fourth parameter is an optional parameter — the “allow overwrite” parameter. If this parameter is set to
1, it will overwrite any existing key named “title” in this struct. If it is set to
0, an error will be thrown if you try to add “title” to a struct that already has a key by that name. The default for this parameter is
0. So, let’s add the rest of our data:
<cfset a = StructInsert(myBook, "author", "David Medlock", 1)> <cfset a = StructInsert(myBook, "description", "Information about CF", 1)> <cfset a = StructInsert(myBook, "publishyear", "2004", 1)> <cfset a = StructInsert(myBook, "ISBN", "ABCD123456", 1)>
Ok, our book contains all the information we need. Now, we want to display our book. This is easy. If you know the names of all the keys for your structure, you can easily display them like this:
<cfoutput> Title: #myBook["title"]#<br /> Author: #myBook["author"]#<br /> Description: #myBook["description"]#<br /> Publish Year: #myBook["publishyear"]#<br /> ISBN: #myBook["ISBN"]# </cfoutput>
Here, we simply dump out the contents of the structure, one key at a time. But, what happens if we don’t know what keys a struct contains? It’s no problem — we can use ColdFusion’s loop tag to output all the keys in the struct.
<cfloop collection="#myBook#" item="key"> <cfoutput> #key#: #myBook[key]#<br /> </cfoutput> </cfloop>
That’s really all we have to do in order to display all the keys in our structure and their values. But, as you’ll notice, this doesn’t output a very pretty label for each item. It just displays the key name. Let’s work on fixing that next.
Storing Structures in Arrays or Other Structures
Just as we can store arrays inside arrays, we can also store structs inside structs and arrays. For example, we can create a struct called titles that will store a user-friendly label for each of the keys in our array. We’ll use the exact same keys we used in our book struct.
<cfset titles = StructNew()> <cfset a = StructInsert(titles, "title", "Title", 1)> <cfset a = StructInsert(titles, "author", "Author", 1)> <cfset a = StructInsert(titles, "description", "Book Description", 1)> <cfset a = StructInsert(titles, "publishyear", "Publish Year", 1)> <cfset a = StructInsert(titles, "isbn", "ISBN Number", 1)>
That was easy. Now, we’ll get a little more complex with our data structures. We’re going to create a struct called
bookshelf and put
titles into it.
<cfset bookshelf = StructNew()> <cfset a = StructInsert(bookshelf, "names", titles, 1)> <cfset a = StructInsert(bookshelf, "values", myBook, 1)>
Here, we simply initialize
bookshelf as a struct and then put two keys into it. The first key is called “
names“, and we put the
titles struct into this key. The second key is called “
values“, and we put the
myBook struct into this. We now have a struct that contains two structs, each of which contains five keys. Now, I want to sort the struct by the name of the key, so I’m going to do this:
<cfset keyList = StructKeyList(bookshelf.names)> <cfset keyList = ListSort(keyList, "TEXT")>
We’ve got a new function here,
StructKeyList, which takes as a parameter the name of a structure. It then gets a list of all the keys and returns these in a comma delimited list. Then, we use the
ListSort function to order the structure keys alphabetically. I do want to point out the method of accessing the structs contained in bookshelf, though. If you’ve worked with any C-style languages, you’ll recognize this as “dot notation”. You might even look at these structures as objects and see that you’re accessing their members. In this case, names is a member of bookshelf. Now, we’ll loop over our list and output the values in each of the two structs.
<cfloop list="#keyList#" index="key"> <cfoutput> #bookshelf.names[key]#: #bookshelf.values[key]#<br /> </cfoutput> </cfloop>
This outputs a nice neat little listing for our book. But, we don’t often come across book stores that sell only one book. So, we’re going to need to keep track of an unlimited number of books here. In order to do this, we’ll be using our
bookshelf struct, and our
myBook struct; we’ll also create a new struct called
myBook2 and an array called
myBookArray. First, we’ll create
<cfset myBook2 = StructNew()> <cfset a = StructInsert(myBook2, "title", "More ColdFusion", 1)> <cfset a = StructInsert(myBook2, "author", "David Medlock", 1)> <cfset a = StructInsert(myBook2, "description", "More ColdFusion Info", 1)> <cfset a = StructInsert(myBook2, "publishyear", "2005", 1)> <cfset a = StructInsert(myBook2, "isbn", "321654DCBA", 1)>
Now, we create a one dimensional array to store our books in.
<cfset myBookArray = ArrayNew(1)>
Next, we’ll add our books to the array:
<cfset myBookArray = myBook> <cfset myBookArray = myBook2>
Now, we have an array containing two structs, each of which contains five keys. We’ll put these books in our bookshelf, and sort them the same way we did in the last example:
<cfset a = StructInsert(bookshelf, "names", titles, 1)> <cfset a = StructInsert(bookshelf, "values", myBookArray, 1)> <cfset keyList = StructKeyList(bookshelf.names)> <cfset keyList = ListSort(keyList, "TEXT")>
Now we’ll display each of our books using two loops. First, we need to make sure both books get displayed. This means we’ll be looping over the array that we’ve stored in
bookshelf.values. Then, we’ll loop over the list of keys and display the label and value for each key in the current array element:
<cfloop from="1" to="#ArrayLen(bookshelf.values)#" index="i"> <cfloop list="#keyList#" index="key"> <cfoutput> #bookshelf.names[key]#: #bookshelf.values[i][key]#<br /> </cfoutput> </cfloop> <hr> </cfloop>
Notice that we use the dot notation to access the array length in our outer loop. Inside that loop, we loop over the list of keys in the array. The interesting part arises when we want to display the values for the title, author, and other fields. We access the bookshelf struct, then the
values key of the
bookshelf struct (which is an array), then the index
i of the
values key (which is a struct), and, finally, we get the value of key from that struct.
Are you now thoroughly confused? The first time I had to use structs at length was quite an experience. But, if you break your task down into simple steps, you’ll find that it’s actually very easy to use ColdFusion’s built-in data structures to enhance your application. Learning these elements of ColdFusion application design and programming can very quickly place you a step ahead of many other CF developers, and it can give you the tools you need to accomplish any task you’re assigned.
Built-In ColdFusion Structs
There are actually some structs that are built into ColdFusion that you probably didn’t even realize were structs. For example, did you know that the Form, URL, and CGI variable scopes are all structs? That’s right. You can easily discover what variables are in each of these structs simply by looping over the appropriate collection. (I know that all these variables appear in the ColdFusion debug information, but sometimes it’s extremely handy to know how to get this information without the aid of CF’s built-in debugging.)
Let’s look at a simple example with the CGI variables, which provide us with essential information about the environment our application runs in. Here’s the code to do this:
<cfloop collection="#CGI#" item="key"> <cfoutput>#key# = #CGI[key]#<br></cfoutput> </cfloop>
That’s it! You can run this very same code to gain information on the Form, URL, CGI, Client, Application, and Session variables. These are all structures from ColdFusion’s point of view, and therefore they are easily accessible using the above method.
That wraps up our introduction to structures in ColdFusion. As you can see, CFML provides some very powerful means of organizing, tracking, and accessing data. You may find that you don’t use these methods very often, but they can often be your saving grace when you’re in a pinch for a solution to a difficult problem. I’ve found structs and arrays to be very helpful when you have complex data that needs to be displayed in unconventional ways. Store these little tidbits of information somewhere in the back of your brain, bookmark this article in your “ColdFusion Resources” folder (I know you have one), and you’ve got one more tool in your development arsenal.