Ask Ben: Iterating Over A ColdFusion XML Document

Posted November 15, 2007 at 7:35 AM

Tags: Ask Ben, ColdFusion

I would appreciate your help, in providing a workable nested solution for the following type of XML structure.

<Info Main>
<Image List>
<Image>
<Image>
<Name List>
<Name>
<Name>
<Name>
<Name>
</Info Main>
<Info Main>
</Info Main>

Where the Info Main is the top structure containing collections of images and names. I have no problem in looping the Info Main top structure as per:

<cfloop index="i" from="1" to="#arrayLen(Info_Main_Array)#"> etc, but I can't seem to work out how to connect the sub-lists of images and names. Your help would be much appreciated.

For starters, let's just make sure that we're all on the same page as to what constitutes a valid XML document in ColdFusion (or anywhere). In a valid XML document, there has to be some sort of root XML node that contains all the other nodes. Also, I don't believe the XML node names can have spaces in them. So, the node "Info Main" is not a valid name. I don't think the parser would be able to tell where the name ends and a poorly formed attribute begins. So, let's take your XML document and convert into something that the ColdFusion XML parser can actually work with:

 Launch code in new window » Download code as text file »

  • <!--- Create the XML document object. --->
  • <cfxml variable="xmlDoc">
  •  
  • <info>
  •  
  • <info-main id="im1">
  •  
  • <image-list id="il1">
  • <image id="i1" />
  • <image id="i2" />
  • </image-list>
  •  
  • <name-list id="nl1">
  • <name id="n1" />
  • <name id="n2" />
  • <name id="n3" />
  • <name id="n4" />
  • </name-list>
  •  
  • </info-main>
  •  
  • <info-main id="im2">
  •  
  • <image-list id="il2">
  • <image id="i3" />
  • <image id="i4" />
  • </image-list>
  •  
  • <name-list id="nl2">
  • <name id="n5" />
  • <name id="n6" />
  • <name id="n7" />
  • <name id="n8" />
  • </name-list>
  •  
  • </info-main>
  •  
  • </info>
  •  
  • </cfxml>

As you can see, I have wrapped your XML nodes into a single root node, info. I have also lower cased all the names (remember XML is very much case sensitive) and I have added hyphens in the node names that had spaces. I have also added ID attributes to each node so that as we traverse the ColdFusion XML document object model, we will easily be able to output the ID to track our progress.

When extracting data from a ColdFusion XML document object, we can get really slick and do some cool XmlSearch() stuff with XPath, but, for this, let's keep it to some simple direct XML node access. To do this, you simply have to understand how the ColdFusion XML document is structured. Each node has a set of attributes (XmlAttributes) and a set of direct child nodes (XmlChildren). The XmlAttributes object is a key-value struct. The XmlChildren is an array.

You can get to each node using these two sets mentioned above, or you can also treat the XML document as a pseudo struct/array document. For example, if we had a parent node containing a child node and we wanted to access the second child of the first parent, we could do this:

xmlDoc.data.XmlChildren[ 1 ].XmlChildren[ 2 ]

... or, we could treat it more like a struct / array beast:

xmlDoc.data.parent[ 1 ].child[ 2 ]

Both would give you the same node reference.

That's not the best example since you can't see the real XML strcuture, so let's get back to your example. Using a combination of the two access methods, we can not iterate over the known structure of our test ColdFusion XML document:

 Launch code in new window » Download code as text file »

  • <!--- Loop over the info-main nodes. --->
  • <cfloop
  • index="intMainIndex"
  • from="1"
  • to="#ArrayLen( xmlDoc.info.XmlChildren )#"
  • step="1">
  •  
  • <!--- Get a short hand for the current info-main node. --->
  • <cfset xmlInfoMain = xmlDoc.info[ "info-main" ][ intMainIndex ] />
  •  
  • info-main[ id = #xmlInfoMain.XmlAttributes.id# ]<br />
  •  
  •  
  • <!--- Get the image-list children. --->
  • <cfset arrImageList = xmlInfoMain[ "image-list" ] />
  •  
  • <!--- Loop over the image list. --->
  • <cfloop
  • index="intImageListIndex"
  • from="1"
  • to="#ArrayLen( arrImageList )#"
  • step="1">
  •  
  • <!--- Get a short hand for the current image-list node. --->
  • <cfset xmlImaegList = arrImageList[ intImageListIndex ] />
  •  
  • . . image-list[ id = #xmlImaegList.XmlAttributes.id# ]<br />
  •  
  •  
  • <!--- Loop over image nodes. --->
  • <cfloop
  • index="intImageIndex"
  • from="1"
  • to="#ArrayLen( xmlImaegList.image )#"
  • step="1">
  •  
  • . . . . image[ id = #xmlImaegList.image[ intImageIndex ].XmlAttributes.id# ]<br />
  •  
  • </cfloop>
  •  
  • </cfloop>
  •  
  •  
  •  
  • <!--- Get the name-list children. --->
  • <cfset arrNameList = xmlInfoMain[ "name-list" ] />
  •  
  • <!--- Loop over the name list. --->
  • <cfloop
  • index="intNameListIndex"
  • from="1"
  • to="#ArrayLen( arrNameList )#"
  • step="1">
  •  
  • <!--- Get a short hand for the current name-list node. --->
  • <cfset xmlNameList = arrNameList[ intNameListIndex ] />
  •  
  • . . name-list[ id = #xmlNameList.XmlAttributes.id# ]<br />
  •  
  •  
  • <!--- Loop over name nodes. --->
  • <cfloop
  • index="intNameIndex"
  • from="1"
  • to="#ArrayLen( xmlNameList.name )#"
  • step="1">
  •  
  • . . . . name[ id = #xmlNameList.name[ intNameIndex ].XmlAttributes.id# ]<br />
  •  
  • </cfloop>
  •  
  • </cfloop>
  •  
  • <br />
  •  
  • </cfloop>

Running the above code, we get the following output:

info-main[ id = im1 ]
. . image-list[ id = il1 ]
. . . . image[ id = i1 ]
. . . . image[ id = i2 ]
. . name-list[ id = nl1 ]
. . . . name[ id = n1 ]
. . . . name[ id = n2 ]
. . . . name[ id = n3 ]
. . . . name[ id = n4 ]

info-main[ id = im2 ]
. . image-list[ id = il2 ]
. . . . image[ id = i3 ]
. . . . image[ id = i4 ]
. . name-list[ id = nl2 ]
. . . . name[ id = n5 ]
. . . . name[ id = n6 ]
. . . . name[ id = n7 ]
. . . . name[ id = n8 ]

I hope this example helps you out in some way.

Download Code Snippet ZIP File

Comments (0)  |  Post Comment  |  Ask Ben  |  Permalink  |  Other Searches  |  Print Page



Keep your Web site content fresh and your overhead costs low with Savvy Content Manager

Reader Comments

There are no comments posted for this web log entry.


Post Comment  |  Ask Ben


Home   |   Web Log   |   ColdFusion   |   Projects   |   Resume   |   Job Form   |   Search   |   Contact
Epicenter Consulting - Custom Software Solutions for Business Evolution HostMySite.com - The Leader In ColdFusion Hosting