When you write XQuery, a large subset of what you're writing is actually XPath 2.0. In fact, XQuery 1.0 is defined formally as an extension to, or superset of, XPath 2.0.
In this series of blog posts, I'm going to talk about the "punctuation" of XPath—all the little marks and what they mean: dot (.), slash (/), slash-slash (//), at-sign (@), dot-dot (..), etc. Since XPath is the common sub-language of both XQuery and XSLT, everything in this series applies both to XQuery and XSLT.
The dot, or period, character (".") in XPath is called the "context item expression" because it refers to the context item. This could be a node (such as an element, attribute, or text node) or an atomic value (such as a string, number, or boolean). When it's a node, it's also called the context node. Try typing "." at the top of your XQuery expression in CQ. What happens?
This is what I get: [1.0-ml] XDMP-CONTEXT: (err:XPDY0002) Expression depends on the context where none is defined:
If we look up the part in parentheses ("XPDY0002"), we'll see that this is the standard message you get when you try to access the context item when none is defined. That's because the context item is not defined at the top level in XQuery.
When "." doesn't yield an error, it returns an item (node or atomic value). Interestingly, those are the only two possibilities: a sequence of one item or an error. Dot (".") will never return an empty sequence or a sequence of more than one item.
In XQuery, by default, the context item (".") is undefined at the top level of expressions (and MarkLogic's implementation does not override that default). However, it's different in XSLT, which has the concept of a current node. The current node, when defined, is what determines the context item at the top level of expressions. XSLT normally assumes the presence of a single source document ("source tree"), whose document node becomes the initial context node. So the normal case in XSLT is the opposite of XQuery: a context item is defined at the top level of expressions. Try running this stylesheet (by copying and pasting the following code into CQ):
The result is not an error in this case but instead the source document (<my-doc/>) is copied to the result. That's because the current node is the source tree's document node (which you can tell from the match="/" part).
So when else is "." defined (besides at the top level of expressions in XSLT)? There are two cases:
- inside a predicate (using "[...]")
- inside a path expression step (to the right of "/")
We'll look at predicates first. Run this expression in CQ:
The predicate filters the sequence to its left, yielding only those items for which the predicate expression ". mod 2 eq 0" returns true. In this case, it yields all the even numbers between 1 and 100 (2, 4, 6, 8, ...). In each case, the "." expression refers to the context item. It gets evaluated exactly 100 times—once for each of the items in the sequence (1 to 100). First, "." returns 1, then 2, then 3, etc.
A predicate can also be applied to a sequence of nodes, or even a heterogeneous sequence of nodes and atomic values. Run this expression in CQ:
In this case, the predicate gets evaluated four times, and "." refers respectively to <foo/>, 5, "a string", and <bar>Hello</bar>. It filters out every item whose value when converted to a string does not equal "Hello". Thus, the result contains just one item: <bar>Hello</bar>.
The context item is also defined whenever a "/" is used in an expression. Let's say we want to take a sequence of nodes and get the value of each one, converted to an upper-case string. For the sake of convenience, let's use a bit of XQuery to define a global variable, giving us a document to work with. Start by entering this into CQ:
A natural way to get what we want would be to use a "for" expression. Add this to the text box in CQ and execute the query:
Sure enough, that gives us what we want:
But we could also just use a "/" along with ".". Replace the "for" expression with the following and run the query again:
In this case, rather than explicitly binding a named variable ($msg), we implicitly bind the context item. "." is evaluated once for each of the items in the sequence returned by $doc/msg. So it's evaluated twice (returning a <msg> element both times) and converted to an upper-case string using the fn:upper-case() function.
One peculiar aspect of the "/" operator is that it can only apply to node sequences. Whereas it's fine if we write this:
We unfortunately can't write:
I'll touch on this again in part 2 of this series on the "/" operator.
One final bit of trivia around "." is that in XPath 1.0 (and XSLT 1.0), "." was just syntax sugar for "self::node()". And that's still what it means—at least when the context item is a node. But XPath 2.0 (and XQuery) introduced the ability to have sequences of values, not just nodes. So in XPath 2.0, "." is no longer a shorthand for something else. It's now a primitive of the language—the "context item expression."