xmlxpathxpath-2.0xmlspyxpath-3.0

XPath: Why does /document-node() match the document node?


An XPath expression of / returns the document node.

An XPath expression of /html is equivalent to /child::html and given an HTML document would return the html element. This is of course evaluated by going to the document node (indicated by the /) and then finding the element child which is an html tag.

Why then does /document-node() actually return the document node?

Given the general XPath expression rules, I would assume /document-node() is equivalent to /child::document-node(), and /child::document-node() should return an empty node sequence (since a document node is never a child of a document node). In fact /child::document-node() does return an empty node sequence, which leads me to believe that /document-node() is not equivalent to /child::document-node(). This seems to violate the general XPath expression rules, where an empty axis is an implied child axis1.

Is there some special rule such that when you have a step of document-node() the axis is assumed to be self instead of child? I'm using the latest version of Altova XMLSpy (2018 sp1). Alternatively, is this a bug in XMLSpy? Or is some part of my understanding of general XPath expression rules incorrect?

Note: For anyone who is trying this out, only XPath 2 and XPath 3 support document-node().

1 Update: As an unrelated FYI, I learned something new from Mads Hansen's answer: in XPath 2 and XPath 3, an empty axis is an implied child axis unless there's an attribute test; if there's an attribute test it's actually an implied attribute axis. So while /html is implicitly /child::html, /attribute() is implicitly /attribute::attribute().


Solution

  • That appears to be a bug in XML Spy.

    3.3.5 Abbreviated Syntax

    1. If the axis name is omitted from an axis step, the default axis is child, with two exceptions: if the NodeTest in an axis step contains an AttributeTest or SchemaAttributeTest then the default axis is attribute; if the NodeTest in an axis step is a NamespaceNodeTest then a static error is raised [err:XQST0134] .

    Verifying with Saxon 9.8.0.8 (HE, PE, EE) and MarkLogic 9.0.3, the XPath /document-node() and /child::document-node() do not select anything.

    These XPaths with different axis names do select the document-node():

    /self::document-node()
    /ancestor-or-self::document-node()
    /*/ancestor::document-node()
    /*/ancestor-or-self::document-node()