如何在具有默认命名空间的 xml 文档上使用 XPath
Posted
技术标签:
【中文标题】如何在具有默认命名空间的 xml 文档上使用 XPath【英文标题】:How to use XPath on xml docs having default namespace 【发布时间】:2011-04-25 18:35:51 【问题描述】:我想操作具有默认命名空间但没有前缀的 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>
【问题讨论】:
这看起来是同一个问题***.com/questions/543049/… XML namespace, JDOM, and XPath 【参考方案1】:我编写了一个简单的NamespaceContext
实现 (here),这可能会有所帮助。它将Map<String, String>
作为输入,其中key
是前缀,value
是命名空间。
它遵循NamespaceContext 规范,您可以在unit tests 中看到它是如何工作的。
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
【讨论】:
【参考方案2】:Blaise Doughan是对的,附上的代码是对的。 问题出在其他地方。我通过 Eclipse IDE 中的应用程序启动器运行所有测试,但没有任何效果。然后我发现 Eclipse 项目是所有悲伤的原因。我从命令提示符运行我的课程,它有效。创建了一个新的 eclipse 项目并在那里粘贴了相同的代码,它也在那里工作。 感谢大家的时间和努力。
【讨论】:
【参考方案3】:使用默认命名空间(无前缀)的文档的 XPath 处理与使用前缀的文档的 XPath 处理相同:
对于命名空间限定的文档,您可以在执行 XPath 时使用 NamespaceContext。您需要在 XPath 中为片段添加前缀以匹配 NamespaceContext。您使用的前缀不需要与文档中使用的前缀匹配。
http://download.oracle.com/javase/6/docs/api/javax/xml/namespace/NamespaceContext.html您的代码如下所示:
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;
注意: 我还使用了Dennis 建议的更正 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();
【讨论】:
所以我将不得不转向命名空间场景。好吧,一个好主意,但我这样做会很痛苦。我有大量的代码目前正在通过使用 xpath 来处理没有命名空间的 xml。我必须添加默认命名空间以进行验证(通过 IDE 和以编程方式)目的。有没有什么办法可以一石两鸟?我的意思是我可能不必编辑所有的 xpath 表达式,同时可以在 IDE 中和以编程方式验证文档? 我想删除命名空间。在这种情况下,我不会遇到 xpath 问题,并且对于编程验证,我可能会在运行时添加命名空间。也许,我只需要在验证之前解析我的文档。这可能是可以接受的,但这样做之后,我看不到任何方法可以通过 IDE 验证我的 xml 文档。还有其他想法吗? 将您的 XPath 更改为 Dennis 建议的内容将使您的原始代码正常工作。不使用命名空间方法。 哦,真的吗?那么一定还有其他一些错误,因为这段代码在我的机器上不起作用。你能帮我找到那个吗? 我添加了适用于我的版本,它使用非命名空间感知 DocumentBuilderFactory。以上是关于如何在具有默认命名空间的 xml 文档上使用 XPath的主要内容,如果未能解决你的问题,请参考以下文章