在下面的示例代码中,任何形式为’// 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?