Parse XML with coldfusion

How would I go about parsing a simple XML document in coldfusion.

Lets say the XML document is like

<XMLDATA>
<Order>
<ID>12</ID>
<data1>1</data1>
<data2>2</data2>
<Product>
<Itemname>Shoes</ItemName>
<Itemprice>2.00</Itemprice>
</Product>
<Product>
<Itemname>Socks</ItemName>
<Itemprice>1.00</Itemprice>
</Product>
</Order>
<Order>
<ID>13</ID>
<data1>1</data1>
<data2>2</data2>
<Product>
<Itemname>Shoes</ItemName>
<Itemprice>2.00</Itemprice>
</Product>
<Product>
<Itemname>Socks</ItemName>
<Itemprice>1.00</Itemprice>
</Product>
</Order>
<Order>
<ID>14</ID>
<data1>1</data1>
<data2>2</data2>
<Product>
<Itemname>Shoes</ItemName>
<Itemprice>2.00</Itemprice>
</Product>
<Product>
<Itemname>Socks</ItemName>
<Itemprice>1.00</Itemprice>
</Product>
</Order>
</XMLDATA>
LVL 2
Matt GrofskyAsked:
Who is Participating?
 
Scott BennettConnect With a Mentor Manager TechnologyCommented:
It is easier to use xmlSearch and xmlParse to find the nodes you want and loop through them like this:
<cfsavecontent variable="xmlstring"><XMLDATA>
<Order>
      <ID>12</ID>
      <data1>1</data1>
      <data2>2</data2>
      <Product>
            <ItemName>Shoes</ItemName>
            <Itemprice>2.00</Itemprice>
      </Product>
      <Product>
            <ItemName>Socks</ItemName>
            <Itemprice>1.00</Itemprice>
      </Product>
</Order>
<Order>
      <ID>13</ID>
      <data1>1</data1>
      <data2>2</data2>
      <Product>
            <ItemName>Shoes</ItemName>
            <Itemprice>2.00</Itemprice>
      </Product>
      <Product>
            <ItemName>Socks</ItemName>
            <Itemprice>1.00</Itemprice>
      </Product>
</Order>
<Order>
      <ID>14</ID>
      <data1>1</data1>
      <data2>2</data2>
      <Product>
            <ItemName>Shoes</ItemName>
            <Itemprice>2.00</Itemprice>
      </Product>
      <Product>
            <ItemName>Socks</ItemName>
            <Itemprice>1.00</Itemprice>
      </Product>
</Order>
</XMLDATA>
</cfsavecontent>
<cfset xmlOrders = xmlSearch(xmlstring,"XMLDATA/Order")>
<cfoutput>
<cfloop from="1" to="#arraylen(xmlOrders)#" index="i">
      <cfset order = xmlparse(xmlorders[i]).order>
      <hr>
      <b>Order ID</b> #Order.ID.XMLText#<br>
      <b>Order Data1</b> #Order.Data1.XMLText#<br>
      <b>Order Data2</b> #Order.Data2.XMLText#<br>
      <table>
            <tr>
                  <td>Item Name</td>
                  <td>Item Price</td>
            </tr>
      <cfset xmlProducts = xmlSearch(order,"Product")>
      <cfloop from="1" to="#arraylen(xmlProducts)#" index="ii">
            <cfset product = xmlparse(xmlProducts[ii]).Product>
            <tr>
                  <td>#product.ItemName.XMLText#</td>
                  <td>#product.Itemprice.XMLText#</td>
            </tr>
      </cfloop>
      </table>
</cfloop>
</cfoutput>

     
0
 
R7AFCommented:
0
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 
Matt GrofskyAuthor Commented:
ya saw this article, it doesnt really show how to drill down into elements to grab data from within sub nodes.
0
 
Matt GrofskyAuthor Commented:
This seems to be the only way I can think of to do it, any other cleaner ways?

<cfset xmlrows = XMLSearch(MyXML,"//XMLDATA") />

<cfloop index="i" from="1" to="#ArrayLen(xmlrows)#">
      <cfloop index="j" from="1" to="#ArrayLen(xmlrows[i].xmlchildren)#">
      #xmlrows[i].xmlchildren[j].XmlName# - #xmlrows[i].xmlchildren[j].XMLText#<BR />
      
      <cfloop index="k" from="1" to="#ArrayLen(xmlrows[i].xmlchildren[j].XmlNodes)#">
      <cfif xmlrows[i].xmlchildren[j].XmlNodes[k].XmlName NEQ "##text">
      Sub Row1: #xmlrows[i].xmlchildren[j].XmlNodes[k].XmlName#: #xmlrows[i].xmlchildren[j].XmlNodes[k].XmlText#<BR />
      
      <cfloop index="L" from="1" to="#ArrayLen(xmlrows[i].xmlchildren[j].XmlNodes[k].XmlNodes)#">
      <cfif xmlrows[i].xmlchildren[j].XmlNodes[k].XmlNodes[L].XmlName NEQ "##text">
      Sub Row2: #xmlrows[i].xmlchildren[j].XmlNodes[k].XmlNodes[L].XmlName#: #xmlrows[i].xmlchildren[j].XmlNodes[k].XmlNodes[L].XmlText#<BR />
      </cfif>
      </cfloop>
0
 
Matt GrofskyAuthor Commented:
ah ok this is what i was looking for to get to that sub node product below order

<cfset order = xmlparse(xmlorders[i]).order>
xmlSearch(order,"Product")>

Thanks.
0
 
Scott BennettManager TechnologyCommented:
yeah that is the tricky part because the xmlsearch results returns sort of goofy data. I figured that one out by getting frustrated and using something like:
<cfset order = xmlparse(xmlorders[i]).order>
while I was grasping for straws. I didn't think it would really work cause it not "normal" cf syntax but it did, so I was happy. Hopefuly I spared you the hairs I had to pull out of my head =)

0
 
mkishlineCommented:
Unless you're anticipating multiple <xmldata> tags in your xml, you're probably just better off doing:
<cfset xmlrows = XMLSearch(MyXML,"//Order") />

Which will result in one less loop.

Other than that, I can't suggest any changes to your logic, but there is a way to simplify the code so that it's a little more readable. You can assign portions of the xml to variables and then use those variables to dictate the flow of the output:

<cfloop index="i" from="1" to="#ArrayLen(xmlrows)#">
      <cfset row_children = xmlrows[i].xmlchildren />
      <cfloop index="j" from="1" to="#ArrayLen(row_children)#">
            <cfset child_nodes = row_children[j].xmlnodes />
            #row_children[j].xmlname# - #row_children[j].xmltext#<br />
            <cfloop index="k" from="1" to="#ArrayLen(child_nodes)#">
                  <cfset grandchildren = child_nodes[k].xmlnodes />
                  <cfif child_nodes[k].xmlname NEQ '##text'>
                        Sub Row1: #child_nodes[k].xmlname#: #child_nodes[k].xmltext#<br />
                  </cfif>
                  <cfloop index="m" from="1" to="#ArrayLen(grandchildren)#">
                        <cfif grandchildren[m].xmlname NEQ '##text'>
                              Sub Row2: #grandchildren[m].xmlname#: #grandchildren[m].xmltext#<br />
                        </cfif>
                  </cfloop>
            </cfloop>
      </cfloop>
</cfloop>
0
 
mkishlineCommented:
Boy, it'd be nice if I double checked the status of a question before posting ;)
0
 
Scott BennettManager TechnologyCommented:
lol I gues I beat you this time... that should make up for yesterday
http://www.experts-exchange.com/Web_Development/Software/ColdFusion_Studio/Q_22733092.html =)
0
 
mkishlineCommented:
well played indeed
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.