javax.xml,XPath 不是从具有命名空间的 XML 中提取的

标签 java xml xpath

有“原始”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 提取 session 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 中提取 session ID?

更新:JDK 1.6

最佳答案

答案是您需要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

关于javax.xml,XPath 不是从具有命名空间的 XML 中提取的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23203421/

相关文章:

java - 为什么我的 play 框架构建有时会获取 oss-parent 依赖项?

java - 使用数据绑定(bind)时,RecyclerView 项目属性会自动更改

java - RecyclerView 在 Groupie 中不可见 (Kotlin)

python - lxml xpath - 获取span标签内的所有文本

java - 时间和内存高效的 Java XPath 解析器

java - 使用来自子类和抽象父类的 protected 成员变量

java - JBoss AS 7 中的 EJB 3 部署

Java android xml文本框没有文本=没有按钮点击

java - Maven:如何在多模块项目中包含 ${project.version}

xml - 使用 Xpath 找到共同的 parent