XPath: using the root elementAuthor: Dave Cassel | Category: Software Development
In XQuery, I commonly find myself writing XPath statements to navigate into some block of XML to find some tasty nugget that’s in there somewhere. When doing so, I’ve found one particular aspect that frequently throws me off, getting me empty results instead of the information I wanted. Having finally figured it out, and after confirming with a friend that I’m not the only one who messes this up, here’s a little lesson to help you write your XPath.
Let’s start with the question that I found confusing: if you want to specify a full XPath from the top node down to what you’re looking for, should you specify the root node? Seems like a simple thing, but as is so often the case, the answer is, “it depends”. Consider this XML:
<doc> <book> <name>The Fellowship of the Ring</name> </book> <author> <name>J. R. R. Tolkien</name> </author> </doc>
I want to retrieve the name of the book using XPath. I can’t just ask for “//name”, because I’d get two results, the book’s name and the author’s. I’ll be more precise and specify the full path. So what XPath do I use: “/doc/book/name” or “/book/name”?
It depends on how we got this chunk of XML. If our XML is a document, then the variable that holds the XML is pointing to the whole document, and <doc/> is the top-level node of that doc. So, assuming that /book.xml contains the XML above:
let $doc := fn:doc('/book.xml') return $doc/doc/book/name
But if the XML is constructed, then the node that holds it is pointing to the top-level node itself — there is no document.
let $str := <doc> <book> <name>The Fellowship of the Ring</name> </book> <author> <name>J. R. R. Tolkien</name> </author> </doc> return $str/book/name
Simple as that. Now a little test: which XPath expression would you use in this case?
let $str := xdmp:unquote(' <doc> <book> <name>The Fellowship of the Ring</name> </book> <author> <name>J. R. R. Tolkien</name> </author> </doc>')
To find the answer, you need to know that xdmp:unquote() returns a document-node() (actually one or more). Now that we know we’ll get a document back, the answer is simple: