Welcome!

ColdFusion Authors: Maureen O'Gara, Hovhannes Avoyan, Yakov Fain, Pat Romanski, Liz McMillan

Related Topics: ColdFusion

ColdFusion: Article

The XPath Factor

XML and XPath

This expression, when run against our XML file, will return a 10-element array, one element for each Iron Chef in each battle. The expression is very simple to follow. The "/" at the beginning of the string tells the XPath engine to start at the root node. Each "/node" combination after the leading "/" tells the XPath engine which set of nested nodes to select and finally return.

You can also start an XPath expression with a double slash "//." A double slash tells the XPath engine to search the entire XML document for the specified node. For example:

<cfset XPathResult = xmlSearch(ironChefXMLObject, "//IronChef")>

will return the same array as:

<cfset XPathResult = xmlSearch(ironChefXMLObject, "/ICA/Battle/IronChef")>

because both expressions are selecting and returning the "IronChef" node.

This XPath shortcut can save the developer a lot of time when parsing through lengthy or deeply nested XML documents. However, since the path is not explicitly listed, it can lead to problems. "/ICA/Battle/IronChef/Score" will return an array with 10 elements, while the expression "//Score," on the other hand, will return an array with 20 elements. This is because the "//Score" expression does not differentiate between the challenger and Iron Chef's scores, thus returning all nodes named "Score."

Besides the nodes that are being returned, the attributes of those nodes are also returned when using XPath. Referencing attributes in XPath is very similar to referencing nodes, with one minor difference. XPath uses the "@attribute" syntax to reference node attributes. All slash "/" and double slash "//" rules apply to the attributes of nodes the same way they apply to nodes themselves.

<cfset XPathResult = xmlSearch(ironChefXMLObject,"//@food")>

The expression "//@food" will return the types of food that both the Iron Chefs and their challengers prepare, while

<cfset XPathResult = xmlSearch(ironChefXMLObject,"/ICA/Battle/IronChef/@food")>

will return only the Iron Chef's culinary style.

The "/", "//," and "@" symbols can be seen as the syntax used in XPath to define the FROM clause commonly used in SQL statements. In order to filter out nodes you will need XPath's equivalent to an SQL WHERE clause. That functionality is realized through XPath's rich set of predicates, functions, and operators.

XPath predicates use a bracket notation similar to the notation used to reference individual elements of an array.

<cfset XPathResult = xmlSearch(ironChefXMLObject, "//Battle[1]")>

As you may have guessed, the expression "//Battle[1]" will return only the first "Battle" node. Likewise "//Battle[2]" will return only the second "Battle" node and so forth. Commonly with arrays you can use the arrayLen() function to find out what the last element's position will be. In XPath you can use the function last() to achieve similar results.

<cfset XPathResult = xmlSearch(ironChefXMLObject, "//Battle[last()]")>

In this expression only the last "Battle" node is returned. Since there is no sorting or ORDER BY mechanism in XPath, nodes are returned in the same order as they appear in the original XML document. Thus the expression "//Battle[last()]" returns the "Battle" node in which potatoes are the secret ingredient, because it is the last one in the XML file.

You can also use a combination of functions and operators to pare down the results returned. This expression will return only the second to last "Battle" node:

<cfset XPathResult = xmlSearch(ironChefXMLObject, "//Battle[last()-1]")>

and this expression will return the first three "Battle" nodes:

   <cfset XPathResult = xmlSearch(ironChefXMLObject,
"//Battle[position()<4]")>

You can also reference the values of nodes using the various set of operators in XPath:

   <cfset XPathResult = xmlSearch(ironChefXMLObject,
"//Battle/IronChef/Score[Total>50]")>

All "Score" nodes that belong to Iron Chefs who scored a total above 50 are returned with this expression. This use of operators can apply to attributes as well as nodes. The following returns all "Battle" nodes where Bobby Flay is the Iron Chef:

   <cfset XPathResult = xmlSearch(ironChefXMLObject,
"//Battle[IronChef/@name='Bobby Flay']")>

and what follows returns all "Challenger" nodes where the challenger cooks Italian food.

   <cfset XPathResult = xmlSearch(ironChefXMLObject,
"//Challenger[@food='Italian']")>

More Stories By Nik Molnar

Nik Molnar is a ColdFusion/Flex developer with over seven years experience. He has led teams through the development of enterprise applications for the mortgage, sports ticketing, and stock industries. He is an amateur Iron Chef and posts regularly at his blog: foodDuo.com. He lives with his wife Katy and his dog Jacques in Orlando, Florida.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.