【问题标题】:javax.xml, XPath is not extracted from XML with namespacesjavax.xml,XPath 不是从带有命名空间的 XML 中提取的
【发布时间】:2014-06-05 20:57:35
【问题描述】:

有“原始”XML

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
    <soap:Header>
        <context xmlns="urn:zimbra">
            <session id="555">555</session>
            <change token="333"/>
        </context>
    </soap:Header>
    <soap:Body>
        <AuthResponse xmlns="urn:zimbraAccount">
            <lifetime>172799999</lifetime>
            <session id="555">555</session>
            <skin>carbon</skin>
        </AuthResponse>
    </soap:Body>
</soap:Envelope>

XML就是这样解析的

// javax.xml.parsers.*
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(pathToXml);

然后我尝试通过 XPath 提取会话 id

// javax.xml.xpath.*;
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
// next xpath does not work with Java and online xpath tester
//XPathExpression expr = xpath.compile("/soap:Envelope/soap:Header/context/session/text()");
// this xpath works with online xpath tester but does not with in Java
XPathExpression expr = xpath.compile("/soap:Envelope/soap:Header/*[name()='context']/*[name()='session']/text()");
String sessionId = (String)expr.evaluate(doc, XPathConstants.STRING);

在这里测试 http://www.xpathtester.com/xpath/678ae9388e3ae2fc8406eb8cf14f3119

当XML被简化成这样

<Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
    <Header>
        <context>
            <session id="555">555</session>
            <change token="333"/>
        </context>
    </Header>
    <Body>
        <AuthResponse xmlns="urn:zimbraAccount">
            <lifetime>172799999</lifetime>
            <session id="555">555</session>
            <skin>carbon</skin>
        </AuthResponse>
    </Body>
</Envelope>

这个 XPath 完成了它的工作

XPathExpression expr = xpath.compile("/Envelope/Header/context/session/text()");

如何使用 Java 从“原始”XML 中提取会话 ID?

更新:JDK 1.6

【问题讨论】:

标签: java xml xpath


【解决方案1】:

答案是你需要correctly use namespaces and namespace prefixes:

首先,在使用 DocumentBuilderFactory 命名空间之前,先调用它,然后再使用它:

factory.setNamespaceAware(true); 

然后执行此操作以检索您想要的值:

XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
xpath.setNamespaceContext(new NamespaceContext() {
    @Override
    public String getNamespaceURI(String prefix) {
        if (prefix.equals("soap")) {
            return "http://www.w3.org/2003/05/soap-envelope";
        }
        if (prefix.equals("zmb")) {
            return "urn:zimbra";
        }

        return XMLConstants.NULL_NS_URI;
    }

    @Override
    public String getPrefix(String namespaceURI) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public Iterator getPrefixes(String namespaceURI) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
});

XPathExpression expr = 
       xpath.compile("/soap:Envelope/soap:Header/zmb:context/zmb:session");
String sessionId = (String)expr.evaluate(doc, XPathConstants.STRING);

您可能需要在文件开头添加一行来导入 NamespaceContext 类:

import javax.xml.namespace.NamespaceContext;

http://ideone.com/X3iX5N

【讨论】:

  • 嗨,JLRishe,不幸的是,这对我不起作用。顺便说一句,我必须使用JDK1.6。
  • NamespaceContext 似乎从 JDK1.5 开始可用:docs.oracle.com/javase/7/docs/api/javax/xml/namespace/…
  • 当我提到 JDK1.6 时,我暗示“switch”构造不适用于 String 对象类型。但这是微不足道的。 “这不起作用” - 这意味着当我用“if->return, if->return”替换开关时,在 XPathExpression 评估后 sessionId 为空。即使我尝试在 XPath 末尾添加“/text()”或“/@id”,sessionId 仍然为空。
  • 好吧,经过 20 分钟的挫折,我终于想起了 DocumentBuilderFactory 具有忽略命名空间的令人愤怒的行为,除非你告诉它要注意它们。请参阅上面我编辑的答案。
  • 现在像魅力一样工作:-)。谢谢!
【解决方案2】:

你总是可以通过忽略命名空间来做到这一点,这不是理想的方法,但有效。

 "/*[local-name()='Envelope']/*[local-name()='Header']/*[local-name()='context']/*[local-name()='session']/text()"

【讨论】:

  • 感谢 Sean F,您的解决方案确实有效。我认为两个同名但命名空间不同的 XML 节点不是很好的设计,对吧?
猜你喜欢
  • 2011-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多