One common XQuery-related question that frequently comes up for developers is why do XQuery and XSLT have more than one operator for each comparison? The table below shows that there are twelve rather than six comparison operators, half of which use letters (such as
eq) and half of which use symbols (such as
|Value Comparison||General Comparison|
|less than or equal to||
|greater than or equal to||
In the 1.0-ml version of XQuery, there’s no difference in behavior by default;
eq behaves the same as
=, etc. If you want to dig a little deeper, this is because of function mapping, which you have the ability to enable or disable; if you disable function mapping,
eq will not behave the same as
However, whereas they behave the same in 1.0-ml, they actually mean different things. The value comparison operators (
lt, etc.) are designed for comparing single values (i.e., sequences of one value each). The general comparison operators (
<, etc.) are designed for comparing sequences of more than one value.
How can I put this to practice?
In the standard 1.0 version of XQuery (which MarkLogic also supports), you’ll get an error if you try to use a value comparison operator to compare sequences of more than one value:
xquery version "1.0"; "foo" eq ("foo","bar")
Here’s the error that results:
The 1.0-ml implementation relaxes this restriction, hence the effectively identical behavior of
=, etc. In XQuery version 1.0, you’d instead need to use a general comparison operator (
"foo" = ("foo","bar")
Using the general comparison operator will return true in both versions 1.0 and 1.0-ml and the expression will return true if any of the items on the left compare successfully with any of the items on the right. This is sometimes called “existential quantification.” A longer, more explicit way to write this in XQuery would be to use a “some” expression:
some $item1 in "foo", $item2 in ("foo","bar") satisfies $item1 eq $item2
You may have a policy (and I think it’s generally a good one) of always writing your code in version 1.0-ml, so does it even matter that you know this difference?
I think so. Knowing the difference enables you to write code that is not only more interoperable, but more expressive of your intentions:
- You may want to write an XQuery 1.0 library that works across multiple implementations
- You may want to better understand the code that’s written in XQuery 1.0 libraries that you use
- You may not want to depend on a XQuery 1.0-ml-specific error fallback behavior
- You may want to more clearly express your intentions in your choice of which operator to use
For example, if you know that
$var will contain at most one number, and you want to compare it with a literal number, it’s best to use the value comparison operator, such as
$var le 5
<= would imply that $var may contain more than one number. On the other hand, if $var suddenly has more than one value, you’d want to use <= instead (to avoid an error in version 1.0), if in fact that’s your intention (i.e. return true if any of $var are less than or equal to the given number):
(: Are any of the numbers in $var less than or equal to 5? :) $var <= 5
Walk through an example
Bringing this to a more practical example, say you have a <person> element in your XML and you want to find the person named “Bill”:
//person[name eq "Bill"]
If you know that a <person> will only ever have one <name>, then the above code is safe. But if you’re using 1.0 and one of your <person> elements has more than one <name>, then this will throw an error. If you’d rather find the <person> element that has any child <name> with a value of “Bill”, then the = operator will work the way you want (in both versions 1.0 and 1.0-ml):
//person[name = "Bill"]
To conclude, I’ll add one historical note. Before XPath 2.0 (which is what XQuery uses), there were no value comparison operators;
lt, and the like, simply didn’t exist. You only had =, >, <, etc. in XSLT/XPath 1.0. With XPath 2.0, XSLT 2.0, and XQuery, you now have a choice.
Read more about Function Mapping in 1.0-ml to better understand why these operators behave the same way.