by Tim Buntel
Product Manager
Allaire Corp.
Structures are everywhere in the ColdFusion world. As of
ColdFusion 4.5, form, application, session, server, request,
and URL variables are stored in structures. Allaire Spectra
makes extensive use of structures and associative arrays.
But what are they and why should you care?
Simply, structures are used to refer to related values
as a unit rather than individually. They provide a way to
group variables logically. Also, with built-in structure
related functions and the ability to nest functions and
arrays, variables become much more powerful.
This article presents an introduction to structures, how
they're coded, and how to capitalize on some of their features.
In addition, the concept of nesting structures and arrays
- one of the most exciting and powerful uses of data in
a ColdFusion application - will be introduced.
Structures and Their Benefits
Simple variables on a given page are just there, blissfully
ignorant of any other variables and happy to store their
value. The benefit of structures lies in the logical grouping
of the variables. For example, an album on compact disc
is an item with several unique values, such as title, artist,
and genre. Although each value is unique, they are part
of a logical unit: the CD itself.
A structure represents the CD and a number of properties,
or keys, within it. By logically grouping the variables
in structures, they can be used as members of a cohesive
unit. For example, examine the following structure:
<CFSCRIPT>
CD=StructNew();
CD.Title = "Cookin at the Plugged Nickel";
CD.Artist = "Miles Davis";
CD.Genre = "Jazz";
</CFSCRIPT>
To view this structure, the following script can be used:
<cfoutput>We have a #CD.Genre# CD called #CD.Title# by #CD.Artist#</cfoutput>
This produces:
We have a Jazz CD called Cookin at the Plugged Nickel by Miles Davis
On the other hand, the StructFind function returns the
value associated with the specified key in the specified
structure:
<cfoutput>We have a #StructFind(CD, "Genre")# CD called #StructFind(CD, "Title")# by #StructFind(CD, "Artist")#</cfoutput>
Here is the return:
We have a Jazz CD called Cookin at the Plugged Nickel by Miles Davis
ColdFusion provides a variety of very handy functions for
working with structures, including StructFind
used in the CD example above. The StructKeyList
function can be used to view (or loop through) a list of
the related variables, such as:
A cd consists of <cfoutput>#StructKeyList(CD)#</cfoutput>.
This returns:
A cd consists of ARTIST,GENRE,TITLE.
The existence of a certain key can be checked with StructKeyExists
(e.g., #StructKeyExists(CD, "PublishedYear")#
returns NO). It can also count the number of keys in a specified
structure, turn the keys into an array, or copy, clear,
and/or delete the structure. Take a look at the ColdFusion
Language Reference documentation for details.
Structures and Arrays: A Dynamic Duo
Structures and arrays can be combined to create complex,
related data sets that are simple and powerful to use. The
CD example provided an interesting way to group three variables
logically. However, it only dealt with one CD. For a more
complicated example, an online music will be used.
Even though "Cookin at the Plugged Nickel" is a fine album,
customers will want to buy other albums as well. If a structure
can be thought of as holding multiple properties of an object,
then arrays can be thought of as holding multiple instances
of an object. When combined, the two produce multiple instances
of objects with multiple properties.
For example, the following code shows a one-dimensional
array titled MyCart.
<CFSCRIPT>
MyCart = ArrayNew(1);
OneCD = StructNew();
OneCD.Title = "Cookin at the Plugged Nickel";
OneCD.Artist = "Miles Davis";
OneCD.Genre = "Jazz";
OneCD.Cost = "15.00";
OneCD.Quantity = "1";
AddIt = ArrayAppend(MyCart, OneCD);
AnotherCD = StructNew();
AnotherCD.Title = "Lady in Satin";
AnotherCD.Atrist = "Billie Holiday";
AnotherCD.Genre = "Blues";
AnotherCD.Cost = "14.00";
AnotherCD.Quantity = "2";
AddIt = ArrayAppend(MyCart, AnotherCD);
</CFSCRIPT>
If the MyCart structure is managed as a session
variable, it becomes a shopping cart that persists through
a user's visit to the store and capable of holding any number
of items and particular information about each item.
Extracting Data from Arrays and Structures
Elements of an array are displayed by indicating their
position in the array, such as ArrayName[position].
Thus, the second element in MyCart would be
displayed as MyCart[2].
Remember the old logic statement, "If A=B and B=C, then
A=C"? Arrays work much the same way. if OneCD.Title
is "Cookin at the Plugged Nickel" and MyCart[1]
is OneCD then MyCart[1].Title
is "Cookin at the Plugged Nickel."
In order to add the contents of the cart together and display
the cost of the items, each item in the array must be counted
- from 1 to ArrayLen(MyCart) - and tallied.
<cfset GrandTotal = 0>
<cfloop index="ThisCD" from="1" to="#ArrayLen(MyCart)#">
<cfset ItemTotal = MyCart[ThisCD].cost * MyCart[ThisCD].quantity>
<cfset GrandTotal = GrandTotal + ItemTotal>
</cfloop>
<cfoutput>So far, your items cost #DollarFormat(GrandTotal)#</cfoutput>
This produces:
So far, your items cost $43.00
Nested Arrays
In the previous example, a structure served as an element
of an array. An array can also serve as a key in a structure.
Nesting arrays within structures and structures within arrays
opens up new worlds of complex data manipulation.
Allaire Spectra uses this technique extensively. For instance,
an Allaire Spectra variable could look like this:
stContainer.aRules[1].stParams.aGroups[1].aObjects[index].METHOD="..."
While intimidating at first, here is a breakdown of the
variable notation in which the nesting scheme becoming obvious:
- There's a structure called stContainer.
- One of stContainer's keys is an array called aRules.
- Each element of the aRules array is a structure.
- One of the keys of that structure is called stParams.
Using the example of an online music store again, a top-level
session variable exists called customer. Each customer may
have both a shopping cart and a "wish list" for things that
he or she wants. Within each of those, multiple CDs exist
with multiple properties for each.
One of the properties of a CD could be a list of all the
tracks on the album. A particular song title would be notated
as:
Customer.ShoppingCart[2].Tracks[3].SongTitle
Listing all of the tracks from the second album in a customer's
cart becomes a simple matter of plugging in the correct
data:
<cfoutput>
#Customer.ShoppingCart[2].AlbumTitle# has the following songs:
<cfloop index="ThisSong" from="1" to="#ArrayLen(Customer.ShoppingCart[2].Tracks)#">
- #Customer.ShoppingCart[2].Tracks[ThisSong].SongTitle#
<cfloop>
</cfoutput>
Conclusion
When data needs to be grouped and related in a hierarchical
manner, such as shopping carts, bills of material, personnel
organizations, site content components (as elegantly demonstrated
in Allaire Spectra), and user profiles, structures and nested
structures and arrays provide powerful and flexible tools
to accommodate any of these cases and more.