For shell scripts and quick checks, five tools on this machine answer the same question (titles of books over $30). xmlstarlet 1.6.1 comes from sudo apt install xmlstarlet:
q='//book[supply/price > 30]/title'
echo "xmllint: $(xmllint --xpath "$q/text()" booknest-catalog.xml)"
echo "xmlstarlet: $(xmlstarlet sel -t -v "$q" booknest-catalog.xml)"
echo "Saxon: $(xquery -s:booknest-catalog.xml -qs:"$q/string()")"
echo "BaseX: $(basex -i booknest-catalog.xml "$q/string()")"
yqq='.catalog.book[] | select((.supply.price."+content" | to_number) > 30) | .title'
echo "yq: $(yq -p xml -o yaml "$yqq" booknest-catalog.xml)"Output
xmllint: Patterns of the Deep Web xmlstarlet: Patterns of the Deep Web Saxon: "Patterns of the Deep Web" BaseX: Patterns of the Deep Web yq: Patterns of the Deep Web
| Tool | Language level | Best for |
|---|---|---|
| xmllint 3,427 (libxml2 3,427 ) | XPath 1.0 | Well-formedness, DTD/XSD/RNG checks |
| xmlstarlet | XPath 1.0, XSLT 1.0 | Editing and selecting in scripts |
| Saxon 726,956 (xquery, xslt3) | XPath/XQuery 3.1, XSLT 3.0 | Real transformations |
| BaseX 693,830 | XQuery 3.1 + Update, Full Text | Repeated queries, databases |
| yq 16,045 (mikefarah) | jq-like paths | Mixed XML, YAML, JSON jobs |
yq turns XML into a YAML-like tree, so an element with attributes keeps its text in +content, and all values are strings: comparing them with a number failed ("!!str not yet supported for comparison") until to_number.