In ColdFusion 10, xmlSearch() added support for XPath 2.0 syntax and passing variables into XPath queries. Using variables can make the query more readable; but, since XML is case-sensitive, it took me a few minutes to get it working. As such, I figured I'd put together a quick demo on using variables in XPath queries.
When using variables in XPath queries, you reference the variable name by prefixing it with a "$". You can then pass a struct of name-value pairs into xmlSearch() as an optional 3rd argument. But, you have to be careful in how you define that struct. My first attempt looked something like this:
<cfscript>
// ...
bestFriends = xmlSearch(
friends,
"//friend[ id/text() = $id ]",
{
id = 4
}
);
// ...
</cfscript>
Notice that I'm passing in "id" and then referencing it as "$id" in the XPath query. Unfortunately, when I ran this code, I got the following ColdFusion error:
Unable to process the result of the XMLSearch for Undeclared variable in XPath expression: $id. ColdFusion is unable to process the result of the XPath search. You may have an undefined variable in the xpath expression.
After some head-scratching, I realized that it was a case-sensitivity issue. XML is case-sensitive, ColdFusion is not. And, what I forgot would happen behind the scenes is that ColdFusion would silently upper-case my struct keys (making the input case different from the reference case). To fix this, I had to quote the variable names when defining the input struct:
<!--- Define our XML document object. --->
<cfxml variable="friends">
<friends>
<friend>
<id>1</id>
<name>Joanna</name>
</friend>
<friend>
<id>2</id>
<name>Tricia</name>
</friend>
<friend>
<id>3</id>
<name>Sarah</name>
</friend>
<friend>
<id>4</id>
<name>Kim</name>
</friend>
</friends>
</cfxml>
<cfscript>
// When passing in variables, make sure to !!quote!! the names. XML is case-sensitive
// and it's important that you explicitly define the case of the variables using quotes;
// otherwise, ColdFusion may upper-case them, making unavailable in the XPath execution.
bestFriends = xmlSearch(
friends,
"//friend[ ( id/text() = $id ) or contains( $names, name/text() ) ]",
{
"id" = 4,
"names" = "Sarah,Jane,Annie"
}
);
// Collect the names and output the list of resultant friends.
names = [];
for ( friend in bestFriends ) {
arrayAppend( names, friend.name[ 1 ].xmlText );
}
writeOutput( "Besties: " & arrayToList( names, ", " ) );
</cfscript>
As you can see, this time, my variable names are quoted. And, when I ran this code, I was able to successfully locate my XML nodes:
Besties: Sarah, Kim
This is a small feature, but a rather nice one. I don't deal with XML much these days; but, it's good to have these tidbits packed away, in the back of my mind, for the occasions that call for some sweet extensible markup language.
Reader Comments
@All,
This is a classic move; I just found an old post that talks about some of the XPath 2.0 updates including... who would have guessed... but an example on how to use variables in xmlSearch():
www.bennadel.com/blog/2340-coldfusion-10-xmlsearch-and-xmltransform-now-support-xpath-2-0.htm
Oh well, good refresher anyway.