加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 当xml具有名称空间前缀时,为什么只有某些XPath表达式才

发布时间:2020-12-15 00:45:42 所属栏目:Java 来源:网络整理
导读:在下面的示例代码中,任何形式为’// elementName’的XPath都会在源xml具有名称空间前缀时返回null(请参阅底部代码中的testWithNS()). 当源xml没有名称空间前缀时,所有列出的XPath表达式都返回一个节点(请参阅testNoNS()). 我知道我可以通过设置NamespaceCont
在下面的示例代码中,任何形式为’// elementName’的XPath都会在源xml具有名称空间前缀时返回null(请参阅底部代码中的testWithNS()).

当源xml没有名称空间前缀时,所有列出的XPath表达式都返回一个节点(请参阅testNoNS()).

我知道我可以通过设置NamespaceContext(如在testWithNSContext()中),将xml解析为名称空间感知文档,并在XPath中使用名称空间前缀来解决这个问题.但是我不想这样做,因为我的实际代码需要处理带有和不带名称空间前缀的xml.

我的问题是为什么它只是:

> //测试
> // child1
> //孙子1
> // child2

返回null,但testWithNS()中的所有其他示例都返回节点?

产量

testNoNS()
test = found
/test = found
//test = found
//test/* = found
//test/child1 = found
//test/child1/grandchild1 = found
//test/child2 = found
//child1 = found
//grandchild1 = found
//child1/grandchild1 = found
//child2 = found

testWithNS()
test = found
/test = found
//test = *** NOT FOUND ***
//test/* = found
//test/child1 = found
//test/child1/grandchild1 = found
//test/child2 = found
//child1 = *** NOT FOUND ***
//grandchild1 = *** NOT FOUND ***
//child1/grandchild1 = found
//child2 = *** NOT FOUND ***

testWithNSContext()
ns1:test = found
/ns1:test = found
//ns1:test = found
//ns1:test/* = found
//ns1:test/ns1:child1 = found
//ns1:test/ns1:child1/ns1:grandchild1 = found
//ns1:test/ns1:child2 = found
//ns1:child1 = found
//ns1:grandchild1 = found
//ns1:child1/ns1:grandchild1 = found
//ns1:child2 = found

import java.io.StringReader;
import java.util.Iterator;

import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.junit.Test;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

public class XPathBugTest {

    private String xmlDec = "<?xml version="1.0" encoding="UTF-8" standalone="yes"?>";
    private String xml = xmlDec + 
        "<test>" +
        "  <child1>" +
        "    <grandchild1/>" +
        "  </child1>" +
        "  <child2/>" +
        "</test>";
    private String xmlNs = xmlDec + 
        "<ns1:test xmlns:ns1="http://www.wfmc.org/2002/XPDL1.0">" +
        "  <ns1:child1>" +
        "    <ns1:grandchild1/>" +
        "  </ns1:child1>" +
        "  <ns1:child2/>" +
        "</ns1:test>";

    final XPathFactory xpathFactory = XPathFactory.newInstance();
    final XPath xpath = xpathFactory.newXPath();

    @Test
    public void testNoNS() throws Exception {
        System.out.println("ntestNoNS()");
        final Document doc = getDocument(xml);

        isFound("test",xpath.evaluate("test",doc,XPathConstants.NODE));
        isFound("/test",xpath.evaluate("/test",XPathConstants.NODE));
        isFound("//test",xpath.evaluate("//test",XPathConstants.NODE));
        isFound("//test/*",xpath.evaluate("//test/*",XPathConstants.NODE));
        isFound("//test/child1",xpath.evaluate("//test/child1",XPathConstants.NODE));
        isFound("//test/child1/grandchild1",xpath.evaluate("//test/child1/grandchild1",XPathConstants.NODE));
        isFound("//test/child2",xpath.evaluate("//test/child2",XPathConstants.NODE));
        isFound("//child1",xpath.evaluate("//child1",XPathConstants.NODE));
        isFound("//grandchild1",xpath.evaluate("//grandchild1",XPathConstants.NODE));
        isFound("//child1/grandchild1",xpath.evaluate("//child1/grandchild1",XPathConstants.NODE));
        isFound("//child2",xpath.evaluate("//child2",XPathConstants.NODE));
    }

    @Test
    public void testWithNS() throws Exception {
        System.out.println("ntestWithNS()");
        final Document doc = getDocument(xmlNs);

        isFound("test",XPathConstants.NODE));
    }

    @Test
    public void testWithNSContext() throws Exception {
        System.out.println("ntestWithNSContext()");
        final Document doc = getDocumentNS(xmlNs);

        xpath.setNamespaceContext(new MyNamespaceContext());

        isFound("ns1:test",xpath.evaluate("ns1:test",XPathConstants.NODE));
        isFound("/ns1:test",xpath.evaluate("/ns1:test",XPathConstants.NODE));
        isFound("//ns1:test",xpath.evaluate("//ns1:test",XPathConstants.NODE));
        isFound("//ns1:test/*",xpath.evaluate("//ns1:test/*",XPathConstants.NODE));
        isFound("//ns1:test/ns1:child1",xpath.evaluate("//ns1:test/ns1:child1",XPathConstants.NODE));
        isFound("//ns1:test/ns1:child1/ns1:grandchild1",xpath.evaluate("//ns1:test/ns1:child1/ns1:grandchild1",XPathConstants.NODE));
        isFound("//ns1:test/ns1:child2",xpath.evaluate("//ns1:test/ns1:child2",XPathConstants.NODE));
        isFound("//ns1:child1",xpath.evaluate("//ns1:child1",XPathConstants.NODE));
        isFound("//ns1:grandchild1",xpath.evaluate("//ns1:grandchild1",XPathConstants.NODE));
        isFound("//ns1:child1/ns1:grandchild1",xpath.evaluate("//ns1:child1/ns1:grandchild1",XPathConstants.NODE));
        isFound("//ns1:child2",xpath.evaluate("//ns1:child2",XPathConstants.NODE));
    }

    private void isFound(String xpath,Object object) {
        System.out.println(xpath + " = " + (object == null ? "*** NOT FOUND ***" : "found"));
    }

    private Document getDocument(final String xml) throws Exception {
        final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        return factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));        
    }

    private Document getDocumentNS(final String xml) throws Exception {
        final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        return factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
    }

    public class MyNamespaceContext implements NamespaceContext {
        @Override
        public String getNamespaceURI(String prefix) {
            if ("ns1".equals(prefix)) {
                return "http://www.wfmc.org/2002/XPDL1.0";
            }
            return XMLConstants.NULL_NS_URI;
        }
        @Override
        public String getPrefix(String uri) {
            throw new UnsupportedOperationException();
        }
        @Override
        public Iterator getPrefixes(String uri) {
            throw new UnsupportedOperationException();
        }
    }
}

撒克逊测试后更新

我现在使用Saxon将XPahtFactory行改为此测试相同的代码

final XPathFactory xpathFactory = new net.sf.saxon.xpath.XPathFactoryImpl();

使用Saxon testWithNS()中的所有行返回*** NOT FOUND ***而不是像’// elementName’那样返回默认的Xalan实现.

鉴于我正在使用非命名空间感知文档构建器工厂来解析xml,为什么这些xpath都不起作用,只有一些使用Xalan?

解决方法

如果要忽略名称空间,可以使用local-name XPath函数:
//*[local-name()='grandchild1']

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读