docwhat's avatardocwhat's blog

XPath has a lousy equality operator

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 File:

<?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>

XSL File:

<?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>

The output:

<?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-value of 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 operations. A map(), reduce(), etc. would all be very handy.  As would some way to write functions. EXSLT helps with this somewhat, but not much.

Ciao!

Comments

Gravatar for http://nick.borko.org/
http://nick.borko.org/

You may want to try doing an operation that returns a result tree fragment, which as I recall never gets turned into a string.

Gravatar for docwhat
docwhat

@nick:

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.

Ciao!

Gravatar for mads hansen
Mads Hansen

A reply that is a couple of years late, but to clarify:

The expression //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 true().

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”.

Gravatar for keith w. boone
Keith W. Boone

Compare generate-id(node1) to generate-id(node2) to compare node equality.

Submit a Comment

docwhat

The personal blog of Christian Höltje.
docwhat docwhat contact