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

前端之家收集整理的这篇文章主要介绍了java – 当xml具有名称空间前缀时,为什么只有某些XPath表达式才能找到节点前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在下面的示例代码中,任何形式为’// elementName’的XPath都会在源xml具有名称空间前缀时返回null(请参阅底部代码中的testWithNS()).

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

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

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

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

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

产量

  1. testNoNS()
  2. test = found
  3. /test = found
  4. //test = found
  5. //test/* = found
  6. //test/child1 = found
  7. //test/child1/grandchild1 = found
  8. //test/child2 = found
  9. //child1 = found
  10. //grandchild1 = found
  11. //child1/grandchild1 = found
  12. //child2 = found
  13.  
  14. testWithNS()
  15. test = found
  16. /test = found
  17. //test = *** NOT FOUND ***
  18. //test/* = found
  19. //test/child1 = found
  20. //test/child1/grandchild1 = found
  21. //test/child2 = found
  22. //child1 = *** NOT FOUND ***
  23. //grandchild1 = *** NOT FOUND ***
  24. //child1/grandchild1 = found
  25. //child2 = *** NOT FOUND ***
  26.  
  27. testWithNSContext()
  28. ns1:test = found
  29. /ns1:test = found
  30. //ns1:test = found
  31. //ns1:test/* = found
  32. //ns1:test/ns1:child1 = found
  33. //ns1:test/ns1:child1/ns1:grandchild1 = found
  34. //ns1:test/ns1:child2 = found
  35. //ns1:child1 = found
  36. //ns1:grandchild1 = found
  37. //ns1:child1/ns1:grandchild1 = found
  38. //ns1:child2 = found

  1. import java.io.StringReader;
  2. import java.util.Iterator;
  3.  
  4. import javax.xml.XMLConstants;
  5. import javax.xml.namespace.NamespaceContext;
  6. import javax.xml.parsers.DocumentBuilderFactory;
  7. import javax.xml.xpath.XPath;
  8. import javax.xml.xpath.XPathConstants;
  9. import javax.xml.xpath.XPathFactory;
  10.  
  11. import org.junit.Test;
  12. import org.w3c.dom.Document;
  13. import org.xml.sax.InputSource;
  14.  
  15. public class XPathBugTest {
  16.  
  17. private String xmlDec = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
  18. private String xml = xmlDec +
  19. "<test>" +
  20. " <child1>" +
  21. " <grandchild1/>" +
  22. " </child1>" +
  23. " <child2/>" +
  24. "</test>";
  25. private String xmlNs = xmlDec +
  26. "<ns1:test xmlns:ns1=\"http://www.wfmc.org/2002/XPDL1.0\">" +
  27. " <ns1:child1>" +
  28. " <ns1:grandchild1/>" +
  29. " </ns1:child1>" +
  30. " <ns1:child2/>" +
  31. "</ns1:test>";
  32.  
  33. final XPathFactory xpathFactory = XPathFactory.newInstance();
  34. final XPath xpath = xpathFactory.newXPath();
  35.  
  36. @Test
  37. public void testNoNS() throws Exception {
  38. System.out.println("\ntestNoNS()");
  39. final Document doc = getDocument(xml);
  40.  
  41. isFound("test",xpath.evaluate("test",doc,XPathConstants.NODE));
  42. isFound("/test",xpath.evaluate("/test",XPathConstants.NODE));
  43. isFound("//test",xpath.evaluate("//test",XPathConstants.NODE));
  44. isFound("//test/*",xpath.evaluate("//test/*",XPathConstants.NODE));
  45. isFound("//test/child1",xpath.evaluate("//test/child1",XPathConstants.NODE));
  46. isFound("//test/child1/grandchild1",xpath.evaluate("//test/child1/grandchild1",XPathConstants.NODE));
  47. isFound("//test/child2",xpath.evaluate("//test/child2",XPathConstants.NODE));
  48. isFound("//child1",xpath.evaluate("//child1",XPathConstants.NODE));
  49. isFound("//grandchild1",xpath.evaluate("//grandchild1",XPathConstants.NODE));
  50. isFound("//child1/grandchild1",xpath.evaluate("//child1/grandchild1",XPathConstants.NODE));
  51. isFound("//child2",xpath.evaluate("//child2",XPathConstants.NODE));
  52. }
  53.  
  54. @Test
  55. public void testWithNS() throws Exception {
  56. System.out.println("\ntestWithNS()");
  57. final Document doc = getDocument(xmlNs);
  58.  
  59. isFound("test",XPathConstants.NODE));
  60. }
  61.  
  62. @Test
  63. public void testWithNSContext() throws Exception {
  64. System.out.println("\ntestWithNSContext()");
  65. final Document doc = getDocumentNS(xmlNs);
  66.  
  67. xpath.setNamespaceContext(new MyNamespaceContext());
  68.  
  69. isFound("ns1:test",xpath.evaluate("ns1:test",XPathConstants.NODE));
  70. isFound("/ns1:test",xpath.evaluate("/ns1:test",XPathConstants.NODE));
  71. isFound("//ns1:test",xpath.evaluate("//ns1:test",XPathConstants.NODE));
  72. isFound("//ns1:test/*",xpath.evaluate("//ns1:test/*",XPathConstants.NODE));
  73. isFound("//ns1:test/ns1:child1",xpath.evaluate("//ns1:test/ns1:child1",XPathConstants.NODE));
  74. isFound("//ns1:test/ns1:child1/ns1:grandchild1",xpath.evaluate("//ns1:test/ns1:child1/ns1:grandchild1",XPathConstants.NODE));
  75. isFound("//ns1:test/ns1:child2",xpath.evaluate("//ns1:test/ns1:child2",XPathConstants.NODE));
  76. isFound("//ns1:child1",xpath.evaluate("//ns1:child1",XPathConstants.NODE));
  77. isFound("//ns1:grandchild1",xpath.evaluate("//ns1:grandchild1",XPathConstants.NODE));
  78. isFound("//ns1:child1/ns1:grandchild1",xpath.evaluate("//ns1:child1/ns1:grandchild1",XPathConstants.NODE));
  79. isFound("//ns1:child2",xpath.evaluate("//ns1:child2",XPathConstants.NODE));
  80. }
  81.  
  82. private void isFound(String xpath,Object object) {
  83. System.out.println(xpath + " = " + (object == null ? "*** NOT FOUND ***" : "found"));
  84. }
  85.  
  86. private Document getDocument(final String xml) throws Exception {
  87. final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  88. return factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
  89. }
  90.  
  91. private Document getDocumentNS(final String xml) throws Exception {
  92. final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  93. factory.setNamespaceAware(true);
  94. return factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
  95. }
  96.  
  97. public class MyNamespaceContext implements NamespaceContext {
  98. @Override
  99. public String getNamespaceURI(String prefix) {
  100. if ("ns1".equals(prefix)) {
  101. return "http://www.wfmc.org/2002/XPDL1.0";
  102. }
  103. return XMLConstants.NULL_NS_URI;
  104. }
  105. @Override
  106. public String getPrefix(String uri) {
  107. throw new UnsupportedOperationException();
  108. }
  109. @Override
  110. public Iterator getPrefixes(String uri) {
  111. throw new UnsupportedOperationException();
  112. }
  113. }
  114. }

撒克逊测试后更新

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

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

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

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

解决方法

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

猜你在找的Java相关文章