StefH / XPath2.Net

Lightweight XPath2 for .NET
Microsoft Public License
36 stars 14 forks source link

Default namespace declaration with empty string as prefix should not break attribute selection #46

Open martin-honnen opened 3 years ago

martin-honnen commented 3 years ago

The fix suggested some months ago to allow using an empty string as the prefix to select e.g. HTML element in the XHTML namespace unfortunately breaks attribute selection, i.e. a test like

      [Fact]
        public void BindingEmptyPrefixShouldNotBreakAttributeSelection()
        {
            var namespaceManager = new XmlNamespaceManager(new NameTable());
            namespaceManager.AddNamespace("", "http://www.w3.org/1999/xhtml");

            var nodeList = GetXHTMLSampleDoc().XPath2SelectNodes("//@lang", namespaceManager);

            Assert.Equal(1, nodeList.Count);
        }

fails as the XPath2 code now looks for attributes named lang in XHTML namespace. I am currently not sure how to fix the NameTest/QName production in XPath.y to only use the context.NamespaceManager.DefaultNamespace if the node name is of an element node.

StefH commented 3 years ago

Just an observation: https://codebeautify.org/Xpath-Tester

image

image

StefH commented 3 years ago

Also note that the original XPath does also not work:

[Fact]
        public void XPath2SelectNodesWithDefaultNamespace()
        {
            var namespaceManager = new XmlNamespaceManager(new NameTable());
            namespaceManager.AddNamespace(string.Empty, "http://www.w3.org/1999/xhtml");

            var nodeListXPath1 = GetXHTMLSampleDoc().SelectNodes("//p", namespaceManager);

            var nodeListXPath2 = GetXHTMLSampleDoc().XPath2SelectNodes("//p", namespaceManager);

            nodeListXPath1.Should().HaveCount(2);
            nodeListXPath2.Should().HaveCount(2);
        }

image

martin-honnen commented 3 years ago

Also note that the original XPath does also not work:


[Fact]
        public void XPath2SelectNodesWithDefaultNamespace()
        {
            var namespaceManager = new XmlNamespaceManager(new NameTable());
            namespaceManager.AddNamespace(string.Empty, "http://www.w3.org/1999/xhtml");

            var nodeListXPath1 = GetXHTMLSampleDoc().SelectNodes("//p", namespaceManager);

Well, that is how XPath 1.0 works, no surprise there.

martin-honnen commented 3 years ago

Just an observation: https://codebeautify.org/Xpath-Tester

I don't get through to that page, it wants me to confirm with too many captchas that I am not a robot.

Is that tool using XPath 1, 2 or 3? Or is it using the XPath2 library? I am not sure what the observation is supposed to tell me or explain me.

StefH commented 3 years ago

I don't know exactly the difference between v1 en v2 in regard to this specific query, So I assumed that this SelectNodes method should just behave the same.

If that is not the case, then I don't know yet how to solve this.

Question: Is this special use-case related that you use the default namespace "http://www.w3.org/1999/xhtml"? So you expect that this default namespace is somehow ignored when selecting the elements with //p ?

martin-honnen commented 3 years ago

In XPath 1 p always selects element nodes with local name p in no namespace. In XPath 2 whether p select element nodes with local name p in no namespace or in the default element namespace depends on the static context https://www.w3.org/TR/xpath20/#dt-static-context:

[Definition: Default element/type namespace. This is a namespace URI or "none". The namespace URI, if present, is used for any unprefixed QName appearing in a position where an element or type name is expected.]

Using namespaceManager.AddNamespace(string.Empty, "http://www.w3.org/1999/xhtml"); is supposed (in my opinion) to set the default element namespace for an XPath2 API integrating itself into the XPathNavigator infrastructure of .NET.

The fix achieved that but is currently flawed as attribute selection also is subjected to the namespace supposed to be only the default element namespace declaration.