NamespaceContext并使用带有XPath的命名空间

Jhe*_*ico 15 java xml xpath

解析包含Java中的命名空间的xpath似乎需要使用NamespaceContext对象,将前缀映射到命名空间URL,反之亦然.但是,NamespaceContext除了自己实现它之外,我找不到任何其他机制.这似乎违反直觉.

问题:是否有任何简单的方法NamespaceContext从文档中获取,或者创建一个或者失败,完全放弃前缀并指定具有完全限定名称的xpath?

McD*_*ell 12

可以在不编写自己的类的情况下获取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));
Run Code Online (Sandbox Code Playgroud)

完全放弃前缀可能会导致表达式含糊不清 - 如果要删除名称空间前缀,则需要更改文档格式.从文档创建上下文不一定有意义.前缀必须与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);
Run Code Online (Sandbox Code Playgroud)

StAX API返回的实现和上面的实现都没有实现doc中定义的完整/方法契约.您可以在此处获得完整的基于地图的实施.


Sup*_*ire 8

我自己一直在使用xpath和NamespaceContexts.我在developerworks上遇到了一个很好的处理问题.

  • 在阅读了IBM的这篇文章后,我可以理解为什么没有默认实现.有多种方法可以解决这个问题.那说:为什么像Apache这样的开源组不会创建不同实现的库? (3认同)

Asa*_*ika 7

我在名为NamespaceContextImpl的" Apache WebServices Common Utilities "中找到了一个方便的实现.

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

<dependency>
    <groupId>org.apache.ws.commons</groupId>
    <artifactId>ws-commons-util</artifactId>
    <version>1.0.1</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

我以下面的方式使用它(我知道它是为sax构建的,但是在阅读完代码之后,它还可以):

NamespaceContextImpl nsContext = new NamespaceContextImpl();
nsContext.startPrefixMapping("foo", "my.name.space.com");
Run Code Online (Sandbox Code Playgroud)

您不需要调用endPrefixMapping.

  • 您仍在对命名空间进行硬编码! (2认同)