ColdFusion Zeus POTW - XPath/XLST Updates

This post is more than 2 years old.

For the most part, I try to avoid XML. I almost always go towards using JSON - both as a consumer and a producer. That being said, probably the only thing I find cool about XML is XPath and XSLT. I haven't used XSLT much, but XPath can be a real useful tool. It allows you to perform queries against XML data (something you can't do with JSON as far as I know). In ColdFusion Zeus, we've upgraded both XSLT and Xpath to version 2 of the specification. Here's some details on this update.

First off - if you want to know everything about XPath2, you can hit up a few URLs to do some deep research:

Now that you've read up, let's look at a few examples. First, our sample XML.

<?xml version="1.0" encoding="ISO-8859-1"?> <bookstore> <book> <title lang="eng">Harry Potter</title> <price>29.99</price> <pages>200</pages> <released>2001-01-01</released> </book> <book> <title lang="eng">Learning XML</title> <price>39.95</price> <pages>100</pages> <released>2003-01-01</released> </book> <book> <title lang="eng">Learning JSON</title> <price>49.95</price> <pages>22</pages> <released>2003-01-01</released> </book> <cd> <title lang="eng">The Downward Spiral</title> <price>39.95</price> <released>2009-01-01</released> </cd> </bookstore>

The primary place XPath2 is updated (at least from what I can tell) is in terms of all the functions that are supported. So for example, you can do a date function search like so:

<cfset booksAfter2002 = xmlSearch(xmlDoc,"/bookstore/book[year-from-date(released) > 2002]")> <cfdump var="#booksAfter2002#" label="Books after 2002">

You can also do interesting math on the XML:

<cfset minpages = xmlSearch(xmlDoc,"/bookstore/book[pages=min(/bookstore/book/pages)]")> <cfdump var="#minpages#" label="Min Pages">

<cfset maxprice = xmlSearch(xmlDoc,"/bookstore/book[price=max(/bookstore/book/price)]")> <cfdump var="#maxprice#" label="Max Price">

<cfset avgprice = xmlSearch(xmlDoc,"avg(/bookstore/book/price)")> <cfoutput>Average price: #dollarFormat(avgprice)#<p></cfoutput>

The first returns the book with the fewest pages, the second the one with the highest price. They both return the full XML node so you have access to the entire block of data. The last one returns an average price for the books: $39.96

How about regular expressions? That works too:

<cfset regex = xmlSearch(xmlDoc,"/bookstore/book[matches(title,""L*arning"")]")> <cfdump var="#regex#" label="Regex">

Sorry that isn't the best regex in the world, but you get the idea. Finally, you can even build expressions that take attributes:

<cfscript> params = {"test"="cd"}; </cfscript> <!--- find all nodes with element name as passed by variable test ---> <cfset result = xmlsearch(xmldoc,"/bookstore/*[local-name() eq $test]", params)> <cfdump var="#result#">

You get the idea. Please note the XSLT has also been updated. Frankly I don't know enough about XSLT 2 to comment on this, but overall, it's a good improvement to ColdFusion's built in XML support.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Ben Nadel posted on 1/6/2012 at 8:40 PM

That's pretty exciting! There are a ton of functions in XPath that look useful. Granted, as you said, JSON is way cooler than XML. But, when you need to use XML, more robust XPath is gonna be sweet!

Comment 2 by Raymond Camden posted on 1/6/2012 at 8:52 PM

It makes me wonder - how do folks search JSON? I mean - I could see turning into a CFML query and doing a QOQ, but XPath is _much_ more direct in this case. (To be fair though, a "good" service would let you do searches/filters/etc before returning the data.)

Comment 3 by Dan G. Switzer, II posted on 1/6/2012 at 8:56 PM

@Raymond:

Just a CSS suggestion, but it would be extremely useful if you updated your CSS to style anchor links, well like links (at least w/in the context of a blog article text.)

Right now they're styled like normal text and very easy to overlook. At bare minimum applying some kind of alternative text styling would help (bold, italics, alt color, etc.)

Maybe you're trying to make them obscure, but I just find it frustrating.

Comment 4 by Raymond Camden posted on 1/6/2012 at 8:57 PM

It looks like just an issue with links in ULs. Will fix. (Later... ;)

Comment 5 by Ben Nadel posted on 1/6/2012 at 9:04 PM

re: Searching JSON, it's an interesting question. I think people have dabbled with "oPath" type things for searching objects. But, for the most part, the JSON data that I deal with doesn't usually need searching. Maybe XML just lends better to a time where responses were less uniform? Even APIs that I see now will return consistent objects, even if certain things failed.

Comment 6 by Jeff Coughlin posted on 1/7/2012 at 4:22 AM

I believe there was a solution 3 or 4 years ago called JSONPath. Haven't played with it since then. I think it was originally written in js though, but was pretty fast. Probably wouldn't be difficult to convert to java or CF. Only problem is whether or not it's a standard or just a cult following :)