namespace-unaware如果Saxon在CLASSPATH上,XPath表达式将失败

Mar*_*tus 5 java xml xpath saxon

我有以下示例XML文件:

<a xmlns="http://www.foo.com">
    <b>
    </b>
</a>
Run Code Online (Sandbox Code Playgroud)

使用XPath表达式/foo:a/foo:b(在其中'foo'正确配置NamespaceContext)我可以正确计算b节点数,并且代码Saxon-HE-9.4.jar在CLASSPATH上和不在时都可以工作.

然而,当我分析了namespace-相同的文件不知道 DocumentBuilderFactory,XPath表达式"/ A/B"正确计数的数量b节点只当Saxon-HE-9.4.jar没有在CLASSPATH.

代码如下:

import java.io.*;
import java.util.*;
import javax.xml.xpath.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import javax.xml.namespace.NamespaceContext;

public class FooMain {

    public static void main(String args[]) throws Exception {

        String xmlSample = "<a xmlns=\"http://www.foo.com\"><b></b></a>";
        {
            XPath xpath = namespaceUnawareXpath();
            System.out.printf("[NS-unaware] Number of 'b' nodes is: %d\n", 
                              ((NodeList) xpath.compile("/a/b").evaluate(stringToXML(xmlSample, false),
                              XPathConstants.NODESET)).getLength());
        }
        {
            XPath xpath = namespaceAwareXpath("foo", "http://www.foo.com");
            System.out.printf("[NS-aware  ] Number of 'b' nodes is: %d\n", 
                              ((NodeList) xpath.compile("/foo:a/foo:b").evaluate(stringToXML(xmlSample, true),
                               XPathConstants.NODESET)).getLength());
        }

    }


    public static XPath namespaceUnawareXpath() {
        XPathFactory xPathfactory = XPathFactory.newInstance();
        XPath xpath = xPathfactory.newXPath();
        return xpath;
    }

    public static XPath namespaceAwareXpath(final String prefix, final String nsURI) {
        XPathFactory xPathfactory = XPathFactory.newInstance();
        XPath xpath = xPathfactory.newXPath();
        NamespaceContext ctx = new NamespaceContext() {
                @Override
                public String getNamespaceURI(String aPrefix) {
                    if (aPrefix.equals(prefix))
                        return nsURI;
                    else
                        return null;
                }
                @Override
                public Iterator getPrefixes(String val) {
                    throw new UnsupportedOperationException();
                }
                @Override
                public String getPrefix(String uri) {
                    throw new UnsupportedOperationException();
                }
            };
        xpath.setNamespaceContext(ctx);
        return xpath;
    }    

    private static Document stringToXML(String s, boolean nsAware) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(nsAware);
        DocumentBuilder builder = factory.newDocumentBuilder();
        return builder.parse(new ByteArrayInputStream(s.getBytes("UTF-8")));
    }


}
Run Code Online (Sandbox Code Playgroud)

运行上面的:

java -classpath dist/foo.jar FooMain
Run Code Online (Sandbox Code Playgroud)

..产生:

[NS-unaware] Number of 'b' nodes is: 1
[NS-aware  ] Number of 'b' nodes is: 1
Run Code Online (Sandbox Code Playgroud)

运行:

java -classpath Saxon-HE-9.4.jar:dist/foo.jar FooMain
Run Code Online (Sandbox Code Playgroud)

...产生:

[NS-unaware] Number of 'b' nodes is: 0
[NS-aware  ] Number of 'b' nodes is: 1
Run Code Online (Sandbox Code Playgroud)

Ian*_*rts 1

XPath 语言仅在命名空间良好形成的 XML 上定义,因此不同处理器在非命名空间感知 DOM 树上的行为(即使是这样的树<a><b/></a>,如果以命名空间感知方式进行解析,实际上也不会使用任何名称空间)充其量是特定于实现的,最坏的是完全未定义。