I just (re-)discovered this bit of stupidity in XPath/XSL. The equal operator will demote node-sets, result-trees, etc. into to strings when compared with a string.
Check out this example:
<?xml version="1.0" encoding="utf-8"?> <nodes> <node>one fish</node> <node>two fish</node> <node>red fish</node> <node>blue fish</node> </nodes>
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> </xsl><xsl :template match="/"> <red -fish> <xsl:value-of select="//node = 'red fish'"/> </red> </xsl>
<?xml version="1.0"?> <red-fish>true</red>
This is ridiculous. How can you be sure that the equal operator is returning what you want if it silently promotes/demotes things? Reading through the section on booleans in the XPath documentation explains how equality works:
If one object to be compared is a node-set and the other is a string, then the comparison will be true if and only if there is a node in the node-set such that the result of performing the comparison on the
string-valueof the node and the other string is true.
It’s almost like it was designed by people who don’t program… or maybe a committee.
This is bad because equality tests will return true in unexpected places. It
also means that the designers of XPath could ignore things like set
reduce(), etc. would all be very handy. As would
some way to write functions. EXSLT helps with this
somewhat, but not much.
You may want to try doing an operation that returns a result tree fragment, which as I recall never gets turned into a string.
Sure, but that’s the same thing as turning the node-set into a string first:
string(//node) = ‘red fish’
At least that’s how I read the Result Tree Fragments section of the XSLT specs.
A reply that is a couple of years late, but to clarify:
//node = ‘red fish’ will compare the computed string value of each of the selected node elements, and if any of the items in the set equal “red fish”, it will return
If you wanted to select the node element’s who’s computed string value is “red fish”, you could use the following:
//node[. = ‘red fish’], which uses a predicate filter to select only the
node element’s who’s computed string value equals “red fish”.
Compare generate-id(node1) to generate-id(node2) to compare node equality.