Java 名称空间上下文和将名称空间与XPath一起使用

Java 名称空间上下文和将名称空间与XPath一起使用,java,xml,xpath,Java,Xml,Xpath,解析Java中包含名称空间的xpath似乎需要使用名称空间上下文对象,将前缀映射到名称空间URL,反之亦然。但是,除了自己实现之外,我找不到任何机制来获取namespacecoxt。这似乎违反直觉 问题是:有没有简单的方法可以从文档中获取namespacecoxt,或者创建一个,或者如果没有,可以完全放弃前缀并使用完全限定的名称指定xpath?无需编写自己的类,就可以获得一个namespacecoxt实例。它的页面显示您可以使用该软件包获取一个 String ctxtTemplate=”“; N

解析Java中包含名称空间的xpath似乎需要使用
名称空间上下文
对象,将前缀映射到名称空间URL,反之亦然。但是,除了自己实现之外,我找不到任何机制来获取
namespacecoxt
。这似乎违反直觉

问题是:有没有简单的方法可以从文档中获取
namespacecoxt
,或者创建一个,或者如果没有,可以完全放弃前缀并使用完全限定的名称指定xpath?

无需编写自己的类,就可以获得一个namespacecoxt实例。它的页面显示您可以使用该软件包获取一个

String ctxtTemplate=”“;
NamespaceContext nsContext=null;
XMLInputFactory=XMLInputFactory.newInstance();
XMLEventReader EVTRADER=工厂
.createXMLEventReader(新的StringReader(ctxtTemplate));
while(evtReader.hasNext()){
XMLEvent event=evtReader.nextEvent();
if(event.isStartElement()){
nsContext=((StartElement)事件)
.getNamespaceContext();
打破
}
}
System.out.println(nsContext.getNamespaceURI(“”);
System.out.println(nsContext.getNamespaceURI(“foo”);
System.out.println(nsContext
.getNamespaceURI(xmlstants.XMLNS_属性);
System.out.println(nsContext
.getNamespaceURI(xmlstants.XML_NS_前缀));
完全放弃前缀可能会导致表达式不明确-如果要删除名称空间前缀,则需要更改文档格式。从文档创建上下文不一定有意义。前缀必须与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);
String xml=“”
+ ""
+“你好”
+ ""
+ "";
字符串表达式=“/stack:data/overflow:value”;
类BaseFooContext实现NamespaceContext{
@凌驾
公共字符串getNamespaceURI(字符串前缀){
如果(“堆栈”。等于(前缀))
返回“http://base";
if(“溢出”。等于(前缀))
返回“http://foo";
抛出新的IllegalArgumentException(前缀);
}
@凌驾
公共字符串getPrefix(字符串名称空间URI){
抛出新的UnsupportedOperationException();
}
@凌驾
公共迭代器getPrefixes(
字符串名称空间(URI){
抛出新的UnsupportedOperationException();
}
}
XPathFactory=XPathFactory.newInstance();
XPath=factory.newXPath();
setNamespaceContext(新的BaseFooContext());
String value=xpath.evaluate(表达式,
新的InputSource(新的StringReader(xml));
系统输出打印项次(值);

StAX API返回的实现和上述实现均未实现文档中定义的完整/合同。您可以得到一个完整的、基于映射的实现。

我自己刚刚使用了xpath和名称空间上下文。我遇到了对这个问题的良好处理。

我在“”中找到了一个名为NamespaceContextImpl的方便实现

您可以使用以下maven依赖项来获取此类:

<dependency>
    <groupId>org.apache.ws.commons</groupId>
    <artifactId>ws-commons-util</artifactId>
    <version>1.0.1</version>
</dependency>

您不需要调用endPrefixMapping。

如果您使用的是Spring框架,那么您可以重用它们的NamespaceContext实现
org.springframework.util.xml.SimpleNamespaceContext

这是一个类似于Asaf Mesika的答案。因此,它不会根据文档自动提供名称空间上下文。你必须自己建造它。它仍然对您有帮助,因为它至少为您提供了一个开始的实现

当我们面临类似的问题时,spring
SimpleNamespaceContext
和“ApacheWebservices公共实用程序”都起了作用。我们希望避免在ApacheWebservices公共实用程序上增加jar依赖,并使用Spring,因为我们的应用程序是基于Spring的

如果您正在使用并且只有默认的XML命名空间(
xmlns=“…”
),则可以使用:


DocumentBuilderFactory docBuilderFactory=DocumentBuilderFactory.newInstance();
setNamespaceAware(true);
DocumentBuilder docBuilder=docBuilderFactory.newDocumentBuilder();
documentdocument=docBuilder.parse(新文件(“Document.xml”);
字符串查询=“/t:Outer/t:internal”;
XPath=XPathFactory.newInstance().newXPath();
字符串xmlns=document.getDocumentElement().getAttribute(“xmlns”);
setNamespaceContext(新的SimpleNameSpaceSolver(“t”,xmlns));
NodeList NodeList=(NodeList)xpath.evaluate(查询、文档、XPathConstants.NODESET);
//节点列表将包含该元素

如果需要,您还可以手动指定
xmlns

这种类型证实了我的担心。除非我自己实现这个类,否则我不能有一个进行任意映射的名称空间上下文。但是XMLStreams示例至少为我提供了一个从静态函数创建NamespaceContext的路径,该静态函数可以像第一个示例中那样构建微型文档。我会试试。是的,没有默认的实现有点痛苦。我认为这很愚蠢。有多少其他在公共API中使用的java接口没有公共可用的具体实现或工厂?您的问题中有一些基本的误解:您可以通过XPath从XML获取所有名称空间URI(在SO中有答案),但不能简单地填充前缀命名空间URI绑定类,因为对于每个节点,它可能是不同的绑定。在选择节点时,您应该提前知道所需元素的名称,其中包括它们的名称空间,您仍然在硬编码名称空间!正是我想要的。javadoc:Meitham——我不知道如何避免硬编码名称空间。通过创建这个名称空间上下文,通过将一个短前缀映射到文档中包含的每个名称空间来初始化它,然后在使用XPath进行搜索时,可以引导XPath搜索
<dependency>
    <groupId>org.apache.ws.commons</groupId>
    <artifactId>ws-commons-util</artifactId>
    <version>1.0.1</version>
</dependency>
NamespaceContextImpl nsContext = new NamespaceContextImpl();
nsContext.startPrefixMapping("foo", "my.name.space.com");