java NamespaceContext 和在 XPath 中使用命名空间
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/914013/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
NamespaceContext and using namespaces with XPath
提问by Jherico
Resolving an xpath that includes namespaces in Java appears to require the use of a NamespaceContextobject, mapping prefixes to namespace urls and vice versa. However, I can find no mechanism for getting a NamespaceContextother than implementing it myself. This seems counter-intuitive.
在 Java 中解析包含命名空间的 xpath 似乎需要使用NamespaceContext对象,将前缀映射到命名空间 url,反之亦然。但是,NamespaceContext除了自己实现之外,我找不到其他机制。这似乎违反直觉。
The question:Is there any easy way to acquire a NamespaceContextfrom a document, or to create one, or failing that, to forgo prefixes altogether and specify the xpath with fully qualified names?
问题:有没有什么简单的方法可以NamespaceContext从文档中获取一个,或者创建一个,或者失败,完全放弃前缀并使用完全限定名称指定 xpath?
采纳答案by McDowell
It is possible to get a NamespaceContextinstance without writing your own class. Its class-usepage shows you can get one using the javax.xml.streampackage.
可以在不编写自己的类的情况下获得NamespaceContext实例。它的类使用页面显示您可以使用javax.xml.stream包获得一个。
String ctxtTemplate = "<data xmlns=\"http://base\" xmlns:foo=\"http://foo\" />";
NamespaceContext nsContext = null;
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLEventReader evtReader = factory
.createXMLEventReader(new StringReader(ctxtTemplate));
while (evtReader.hasNext()) {
XMLEvent event = evtReader.nextEvent();
if (event.isStartElement()) {
nsContext = ((StartElement) event)
.getNamespaceContext();
break;
}
}
System.out.println(nsContext.getNamespaceURI(""));
System.out.println(nsContext.getNamespaceURI("foo"));
System.out.println(nsContext
.getNamespaceURI(XMLConstants.XMLNS_ATTRIBUTE));
System.out.println(nsContext
.getNamespaceURI(XMLConstants.XML_NS_PREFIX));
Forgoing prefixes altogether is likely to lead to ambiguous expressions - if you want to drop namespace prefixes, you'd need to change the document format. Creating a context from a document doesn't necessarily make sense. The prefixes have to match the ones used in the XPath expression, not the ones in any document, as in this code:
完全放弃前缀可能会导致表达不明确 - 如果您想删除名称空间前缀,则需要更改文档格式。从文档创建上下文不一定有意义。前缀必须匹配 XPath 表达式中使用的前缀,而不是任何文档中的前缀,如以下代码所示:
String xml = "<data xmlns=\"http://base\" xmlns:foo=\"http://foo\" >"
+ "<foo:value>"
+ "hello"
+ "</foo:value>"
+ "</data>";
String expression = "/stack:data/overflow:value";
class BaseFooContext implements NamespaceContext {
@Override
public String getNamespaceURI(String prefix) {
if ("stack".equals(prefix))
return "http://base";
if ("overflow".equals(prefix))
return "http://foo";
throw new IllegalArgumentException(prefix);
}
@Override
public String getPrefix(String namespaceURI) {
throw new UnsupportedOperationException();
}
@Override
public Iterator<String> getPrefixes(
String namespaceURI) {
throw new UnsupportedOperationException();
}
}
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext(new BaseFooContext());
String value = xpath.evaluate(expression,
new InputSource(new StringReader(xml)));
System.out.println(value);
Neither the implementation returned by the StAX API nor the one above implement the full class/methodcontracts as defined in the doc. You can get a full, map-based implementation here.
回答by Suppressingfire
I've just been working through using xpath and NamespaceContexts myself. I came across a good treatment of the issue on developerworks.
我自己一直在努力使用 xpath 和 NamespaceContexts。我在 developerworks 上遇到了对这个问题的很好的处理。
回答by Asaf Mesika
I found a convenient implementation in "Apache WebServices Common Utilities" called NamespaceContextImpl.
我在名为 NamespaceContextImpl 的“ Apache WebServices Common Utilities”中找到了一个方便的实现。
You can use the following maven dependency to obtain this class:
您可以使用以下 maven 依赖项来获取此类:
<dependency>
<groupId>org.apache.ws.commons</groupId>
<artifactId>ws-commons-util</artifactId>
<version>1.0.1</version>
</dependency>
I've use it in the following manner (I know its built for sax, but after reading the code, its o.k):
我以下列方式使用它(我知道它是为 sax 构建的,但在阅读代码后,它可以):
NamespaceContextImpl nsContext = new NamespaceContextImpl();
nsContext.startPrefixMapping("foo", "my.name.space.com");
You don't need to called endPrefixMapping.
您不需要调用 endPrefixMapping。
回答by bartolom
If you are using the Spring framework you can reuse their NamespaceContext implementation
org.springframework.util.xml.SimpleNamespaceContext
如果您使用的是 Spring 框架,则可以重用它们的 NamespaceContext 实现
org.springframework.util.xml.SimpleNamespaceContext
This is a similar answer like the one from Asaf Mesika. So it doesn't give you automatic a NamespaceContext based on your document. You have to construct it yourself. Still it helps you because it at least gives you an implementation to starts with.
这是一个类似于 Asaf Mesika 的答案。因此,它不会根据您的文档自动为您提供 NamespaceContext。你必须自己构建它。它仍然对你有帮助,因为它至少为你提供了一个开始的实现。
When we faced a similar problem, Both the spring SimpleNamespaceContextand the "Apache WebServices Common Utilities" worked. We wanted to avoid to the addition jar dependency on Apache WebServices Common Utilities and used the Spring one, because our application is Spring based.
当我们遇到类似的问题时,springSimpleNamespaceContext和“Apache WebServices Common Utilities”都有效。我们想避免对 Apache WebServices Common Utilities 的附加 jar 依赖并使用 Spring,因为我们的应用程序是基于 Spring 的。
回答by Ben Hutchison
If you are using Jersey 2and only have a default XML namespace (xmlns="..."), you can use SimpleNamespaceResolver:
如果您使用的是Jersey 2并且只有一个默认的 XML 命名空间 ( xmlns="..."),您可以使用SimpleNamespaceResolver:
<?xml version="1.0" encoding="UTF-8"?>
<Outer xmlns="http://host/namespace">
<Inner />
</Outer>
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
docBuilderFactory.setNamespaceAware(true);
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document document = docBuilder.parse(new File("document.xml"));
String query = "/t:Outer/t:Inner";
XPath xpath = XPathFactory.newInstance().newXPath();
String xmlns = document.getDocumentElement().getAttribute("xmlns");
xpath.setNamespaceContext(new SimpleNamespaceResolver("t", xmlns));
NodeList nodeList = (NodeList) xpath.evaluate(query, document, XPathConstants.NODESET);
//nodeList will contain the <Inner> element
You can also specify xmlnsmanually if you want.
xmlns如果需要,您也可以手动指定。

