XPath String Comparison Against Numeric Values
When evaluating XML attributes against numeric values, XPath does not
perform a textual comparison; instead, it automatically coerces strings
and node-sets into numbers before executing the comparison. If an
attribute contains a valid numeric representation, it is cast to a
floating-point number and compared mathematically. If the attribute
string cannot be parsed as a valid number, it converts to
NaN (Not-a-Number), which causes the comparison to evaluate
to false.
The Core Type Coercion Rule
In XPath 1.0, comparison operators (=, !=,
<, <=, >,
>=) follow strict precedence rules for data types. If
one operand in an expression is a number and the other is a string or a
node-set (such as an XML attribute), the non-numeric operand is
automatically converted to a number using the internal
number() function.
For example, consider the following XML element:
<product id="101" price="29.99" code="A50" />When evaluating the XPath query:
//product[@price > 20]
XPath processes the expression in these steps: 1. Identifies that the
right-hand operand (20) is a number. 2. Extracts the string
value of the @price attribute ("29.99"). 3.
Converts "29.99" to the numeric float 29.99.
4. Evaluates 29.99 > 20, which returns
true.
Handling Non-Numeric
Strings and NaN
If an attribute contains characters that do not form a valid numeric
literal, the number() conversion fails and produces
NaN.
In XPath, any comparison involving NaN using standard
relational operators (=, <,
<=, >, >=) returns
false.
For example, with the expression:
//product[@code > 10]
- The string value
"A50"is converted vianumber("A50"), resulting inNaN. - The comparison
NaN > 10is evaluated. - The result is
false, and the element is not selected.
Note on inequality (!=): In XPath 1.0,
comparing a string that becomes NaN with a number using
!= also evaluates to true if comparing
primitives directly, but comparing a node-set containing
NaN to a number via != can yield
counter-intuitive results because NaN != number is
mathematically true.
Equality vs. Relational Comparisons
Type conversion behavior depends on the operator and operand types:
- Number to String Equality (
@attr = 5): The string attribute is converted to a number. If@attris"05",number("05")becomes5, and5 = 5evaluates totrue. - String to String Equality
(
@attr = '5'): Both operands are strings, so lexical comparison occurs. If@attris"05","05" = "5"evaluates tofalse.
XPath 2.0+ and Schema Awareness
In XPath 2.0, 3.0, and 3.1: * Without an XML Schema, attribute values
are typed as xs:untypedAtomic. When compared with a numeric
literal, the xs:untypedAtomic value is implicitly cast to
xs:double. * If the cast fails (e.g., comparing
"A50" to 10), XPath 2.0+ raises a dynamic
error (FORG0001) rather than silently converting the value
to NaN. * With an XML Schema, if the attribute is
explicitly typed (e.g., xs:integer or
xs:decimal), strong typing rules apply, and direct numeric
comparison is performed natively without fallback casting errors.