Previously I explained how to create a function to recurse through a specific type of XML document and return the XML data in an array. It worked just fine, but I realized that the function could be made even more generic so that it could also handle any type of XML.
Building on the concept of using recursive functions to parse XML documents, I'll explain how to create a full set of custom functions to interact with and manipulate the XML elements. I will also wrap it all up in a ColdFusion Component for ease of use and portability.
Rundown of the custom functions
ColdFusion MX has some predefined XML functions, but they are somewhat limited. Most involve things like creating an XML object, or inserting new elements into an existing XML object. To build a generic XML recursion function, I'll need a series of custom functions to handle the bulk of the work. A nice benefit of doing this is that the custom functions can be used on their own, outside of the recursion function, to provide some nice additional XML functions to your toolkit.
Here is a list of the custom XML functions that I thought would be useful, along with descriptions of what they do:
- getRootElement()—Given a complete XML object, returns the root element object
- hasXMLChildren()—Returns true if the passed XML element has child elements
- getXMLChildCount()—Returns the number of child elements of the passed element
- getXMLChildElement()—Returns the specified child element of the passed element
- hasXMLAttributes()—Returns true if the passed element has attributes
- getXMLAttributes()—Returns the attributes of the passed element
- getXMLAttributeValue()—Returns the specified attribute from the passed attributes structure
- hasXMLElementName()—Returns true if the passed element contains an element with the specified name
- getXMLElementName()—Returns the specified element from the passed XML element
- hasXMLElementText()—Returns true if the passed element has XML text
- getXMLElementText()—Returns the XML text of the passed element
With this set of functions to build upon, creating a generic XML recursion function was relatively straightforward. The final result is a function called recurseXMLObject(). To use it, you pass in a ColdFusion XML object, and it returns an array of structures containing XML data.
Each array element has structure keys for elementName and nodeDepth. The key, nodeDepth, represents the position of the element in the original XML, and is handy for doing things like properly indenting the data if you want to display it.
An array element can also contain a structure called attributes, which matches the particular attributes of the XML element. Another possible structure key is the array elementText, which represents XML text, if the XML element has any. XML text is the data contained between an XML tag set.
I also wanted to build in the option to not return everything from the XML data. Sometimes XML data can be large, and you might only want to deal with elements with specific names. The recurseXMLObject() function takes an optional argument, a comma-delimited list of element names to capture. In other words, elements that don't match one of the values in the filter list are excluded from the resulting array.
Finally, all of these functions are wrapped into a ColdFusion component called xmlUtils.cfc. You can see the final code for xmlUtils.cfc in Listing A.
Using the xmlUtils CFC
To use the xmlUtils CFC, just read in some XML and then parse it with the ColdFusion xmlParse() function to transform it into a ColdFusion XML Object. Then pass the root element of your XML Object into the recurseXMLObject() function of the CFC, as shown in Listing B.
To test this, I grabbed a random XML file out of my Oracle 9i folder and ran it through the function. You can see the XML in Listing C.
The result, output with <cfdump>, is shown in Figure A:
You could easily loop over the result array to do other things with the data, or to output it to the screen. If you only wanted to get back XML elements with the name "user," you would call the function as shown in Listing D.
The result array will now contain only data for <user> XML elements.
I've created a useful set of XML manipulation functions to use with ColdFusion MX applications. I hope you'll find some uses for this set of functions within your own applications. If you have any problems or suggestions, post to the discussion thread for this article.