如何在具有默认名称空间的xml文档上使用XPath

我想操纵默认的命名空间,但没有前缀的XML文档。 有没有一种方法来使用没有命名空间uri的xpath,就像没有命名空间一样?
我相信它应该是可能的,如果我们将documentBuilderFactory的namespaceAware属性设置为false。 但在我的情况下,这是行不通的。
我的理解是不正确的,或者我在代码中犯了一些错误?

这是我的代码:

DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); domFactory.setNamespaceAware(false); try { DocumentBuilder builder = domFactory.newDocumentBuilder(); Document dDoc = builder.parse("E:/test.xml"); XPath xPath = XPathFactory.newInstance().newXPath(); NodeList nl = (NodeList) xPath.evaluate("//author", dDoc, XPathConstants.NODESET); System.out.println(nl.getLength()); } catch (Exception e) { e.printStackTrace(); } 

这是我的xml:

 <?xml version="1.0" encoding="UTF-8"?> <root xmlns="http://www.mydomain.com/schema"> <author> <book title="t1"/> <book title="t2"/> </author> </root> 

使用默认名称空间(无前缀)的文档的XPath处理与使用前缀的文档的XPath处理相同:

对于命名空间限定的文档,您可以在执行XPath时使用NamespaceContext。 您需要在XPath中join片段前缀以匹配NamespaceContext。 您使用的前缀不需要与文档中使用的前缀匹配。

下面是你的代码的外观:

 import java.util.Iterator; import javax.xml.namespace.NamespaceContext; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; public class Demo { public static void main(String[] args) { DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); domFactory.setNamespaceAware(true); try { DocumentBuilder builder = domFactory.newDocumentBuilder(); Document dDoc = builder.parse("E:/test.xml"); XPath xPath = XPathFactory.newInstance().newXPath(); xPath.setNamespaceContext(new MyNamespaceContext()); NodeList nl = (NodeList) xPath.evaluate("/ns:root/ns:author", dDoc, XPathConstants.NODESET); System.out.println(nl.getLength()); } catch (Exception e) { e.printStackTrace(); } } private static class MyNamespaceContext implements NamespaceContext { public String getNamespaceURI(String prefix) { if("ns".equals(prefix)) { return "http://www.mydomain.com/schema"; } return null; } public String getPrefix(String namespaceURI) { return null; } public Iterator getPrefixes(String namespaceURI) { return null; } } } 

注意:我也使用了Dennisbuild议的更正的XPath。

以下内容似乎也起作用,并且更接近您的原始问题:

 import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; public class Demo { public static void main(String[] args) { DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); try { DocumentBuilder builder = domFactory.newDocumentBuilder(); Document dDoc = builder.parse("E:/test.xml"); XPath xPath = XPathFactory.newInstance().newXPath(); NodeList nl = (NodeList) xPath.evaluate("/root/author", dDoc, XPathConstants.NODESET); System.out.println(nl.getLength()); } catch (Exception e) { e.printStackTrace(); } } } 

Blaise Doughan是对的,附加代码是正确的。
问题是在某个地方select。 我在Eclipse IDE中通过应用程序启动器运行所有的testing,并没有任何工作。 然后我发现Eclipse项目是所有悲伤的原因。 我从命令提示符运行我的课程,它的工作。 创build一个新的eclipse项目,并在那里粘贴相同的代码,它也在那里工作。 谢谢大家的时间和努力。

我写了一个简单的NamespaceContext实现( 这里 ),这可能是有帮助的。 它将一个Map<String, String>作为input,其中key是一个前缀,并且该value是一个名称空间。

它遵循NamespaceContext规范,你可以看到它在unit testing中是如何工作的。

 Map<String, String> mappings = new HashMap<>(); mappings.put("foo", "http://foo"); mappings.put("foo2", "http://foo"); mappings.put("bar", "http://bar"); context = new SimpleNamespaceContext(mappings); context.getNamespaceURI("foo"); // "http://foo" context.getPrefix("http://foo"); // "foo" or "foo2" context.getPrefixes("http://foo"); // ["foo", "foo2"] 

请注意,它依赖于Google Guava