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]
  1. The string value "A50" is converted via number("A50"), resulting in NaN.
  2. The comparison NaN > 10 is evaluated.
  3. 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:

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.