Comparisons and Set Operators

Sequence Comparisons and Set Operators

XPath has three kinds of comparison. General comparisons (=, !=, <, <=, >, >=) work on whole sequences and are existential: (1, 2) = (2, 3) is true because some pair matches. Value comparisons (eq, ne, lt, le, gt, ge) compare exactly one item with one item and raise an error otherwise. Node comparisons compare identity (is) and document order (<<, >>). For node sequences, | (or union), intersect and except are set operations by identity, returning document order without duplicates:

General, value and node comparisons, and set operators on books
xp '(1, 2) = (2, 3)' '(1, 2) != (1, 2)' '(1, 2) eq (2, 3)' '//book[1]/pages eq 312' \
   '//book[1]/pages = 312' '"10" lt "9"' '(//book[2] | //book[1] | //book[1]) ! string(@id)' \
   '(//book[pages > 300] intersect //book[supply/price < 20]) ! string(@id)'
Output
(1, 2) = (2, 3)                        => true()
(1, 2) != (1, 2)                       => true()
(1, 2) eq (2, 3)                       => error XPTY0004
//book[1]/pages eq 312                 => error XPTY0004
//book[1]/pages = 312                  => true()
"10" lt "9"                            => true()
(//book[2] | //book[1] | //book[1]) ! string(@id) => "b1" "b2"
(//book[pages > 300] intersect //book[supply/price < 20]) ! string(@id) => "b1" "b5"

(1, 2) != (1, 2) is true because 1 differs from 2; for "no item equals", write not($a = $b). And pages eq 312 fails: a value comparison casts untyped text to xs:string, which cannot meet an integer, whereas = casts it to the other operand's type. Use = on untyped data or cast first (xs:integer(pages) eq 312); strings compare as strings, so "10" lt "9".