Default Namespaces and Scoping

Omit the prefix, xmlns="namespace-URI", and you declare a default namespace for the element and every unprefixed element below it. An inner declaration overrides an outer one, and xmlns="" undeclares the default. ONIX, XHTML, SVG and Atom all use default namespaces, so their documents carry no prefixes. The rule that trips everyone: a default namespace never applies to attributes, and an unprefixed XPath name test matches only elements in no namespace. Put the catalog into a namespace and watch the plain query fail:

A default namespace renames every element, but not the attributes
sed 's|<catalog |<catalog xmlns="https://booknest.example.com/ns/catalog" |' \
  booknest-catalog.xml > booknest-catalog-ns.xml
xquery -s:booknest-catalog-ns.xml -qs:'count(//book), count(//*:book)'
xquery -s:booknest-catalog-ns.xml -qs:'declare default element namespace
  "https://booknest.example.com/ns/catalog";
  count(//book), //book[1]/@id ! namespace-uri(.), //book[1]/title ! namespace-uri(.)'
Output
0
6
6
""
"https://booknest.example.com/ns/catalog"

//book finds nothing, because the elements are now {https://booknest.example.com/ns/catalog}book. The wildcard *:book matches any namespace, handy at the prompt but sloppy in production. Declare the namespace to the query language instead: declare default element namespace in XQuery, xpath-default-namespace in XSLT, or a prefix map for lxml 3,063 's xpath() (Python and XML with lxml). When a partner's feed suddenly yields no rows, check its root element first: a namespace changed upstream silently empties every path expression.