Skip to main content
Ben Nadel at InVision In Real Life (IRL) 2018 (Hollywood, CA) with: Mike Frey
Ben Nadel at InVision In Real Life (IRL) 2018 (Hollywood, CA) with: Mike Frey

Accessing XML Nodes Having Names That Contain Dashes In ColdFusion

By
Published in Comments (3)

ColdFusion has always made working with XML documents very easy. By implicitly wrapping the underlying XML DOM nodes in pseudo node collections, we've always been able to easily access XML nodes using struct (dot) and array (bracket) notation. For example, accessing the name of the third friend in an XML document could look as straightforward as something like this:

friends.friend[ 3 ].name.xmlText

As you can see, ColdFusion allows us to think about XML node collections as both named and ordered collections of like-nodes.

Most of the time, this is exactly what we need and it works perfectly. But, as Simon Hume brought up on Twitter today, when your XML node names contain a dash, you have to be a bit more careful in the way you define your node paths. Going back to the previous example, if we had the node, "friend-name", rather than, "name," we might be tempted to try following node path:

friends.friend[ 3 ].friend-name.xmlText

When ColdFusion sees this, however, it will throw the following error:

Element FRIEND is undefined in a Java object of type class coldfusion.xml.XmlNodeMap.

This is happening because ColdFusion doesn't see the dash as part of the node name; rather, ColdFusion sees this dash as a mathematical operator in the following equation:

((friends.friend[ 3 ].friend) - (name.xmlText))

To get ColdFusion to see the dash as part of the node name, we have to "escape" it, for lack of a better term. To do so, we either have to use array notation and define the node name as a quoted string; or, we have to use xmlSearch() where we can deal directly with the underlying document object model. The following code demonstrates both of these approaches:

<!---
	Create an XML document that has some node with names that
	contain dashes.
--->
<cfxml variable="friends">

	<friends>
		<friend>
			<given-name>Tricia</given-name>
			<private-name>Pookie-bear</private-name>
		</friend>
		<friend>
			<given-name>Joanna</given-name>
			<private-name>Sugar-butt</private-name>
		</friend>
	</friends>

</cfxml>


<!---
	Use ColdFusion's XML node wrappers to access the pseudo-node
	collection based on names. Notice here that we are wrapping the
	node name in quotes and using array-notation in the node path.
--->
<cfset tricia = friends.friends.friend[ 1 ][ "private-name" ].xmlText />

<!---
	In this version, we'll use xmlSearch(). Since xmlSearch() is
	using the native XML DOM structure, we don't need to "escape"
	the dashed name in any way.
--->
<cfset joanna = xmlSearch(
	friends,
	"/friends/friend[ 2 ]/private-name/"
	) />

<!---
	Output the friend's private names as extracted from the XML
	document object model.

	NOTE: Because xmlSearch() returns an array, "joanna" is the XML
	node array at this point, not the actual text value.
--->
<cfoutput>

	Tricia: #tricia#
	<br />
	<br />
	Joanna: #joanna[ 1 ].xmlText#

</cfoutput>

As you can see in the above code, our ColdFusion XML document has the dash-containing node, "private-name." In the first approach, we use array notation and quote the node name. In the second approach, we use xmlSearch() in which no "escaping" is necessary. Running the above code, we get the following page output:

Tricia: Pookie-bear

Joanna: Sugar-butt

As you can see, both approaches work fine when dealing with XML nodes that contain dashed-names. The technique you end up using is going to depend on the situation. Using ColdFusion's pseudo node wrappers is typically easier when we know that the structure of the XML document will be fairly static. But, if the XML document can be more dynamic, xmlSearch() gives us a lot of flexibility and power in how we traverse the underlying node tree.

Want to use code from this post? Check out the license.

Reader Comments

15,902 Comments

You could also use native XML traversal to get around this:

xmlRoot.xmlChildren[ 1 ].xmlChildren[ 2 ].xmlText

... but this is pretty much unreadable. As such, I left it out of the convesation; but, I figured I'd throw it here into the comments as an after-thought.

1 Comments

I ran into this issue with an XML attribute, here is how I worked around it...

<cfset example = XmlRoot.XmlAttributes["page-size"]>

...where "page-size" is an XML attribute of the root node. I figure this may be somewhat easier to follow as there is no extraneous array notation, or XML searching involved.

15,902 Comments

@Justin,

Ah, great points - the array notation works both for element nodes as well as for attribute nodes. Excellent tip.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel