使用具有不同命名空间的XPATH导航XML

时间:2016-02-11 13:20:33

标签: java xml xpath

我正在努力找出如何导航到使用命名空间的xml区域。使用基本的xpath我可以很好地导航到消息详细信息节点,但我不确定在进入该块时我需要做什么,因为内部的所有内容都使用命名空间。请有人帮忙吗?

谢谢

   <?xml version="1.0" encoding="UTF-8"?>
    <Message>
        <MessageList>
            <MessageCount>2</MessageCount>
            <DateTimeStamp>2016-02-11T12:50:26</DateTimeStamp>
            <MessageDetail>
                <MessageID>2332445456767</MessageID>
                <Env:MessageContainer xmlns:Env="http://www.somesite.com/schema/v1.0/envelope" xmlns:BS="http://www.somesite.com/schema/v1.0/BusinessServices">
                    <Env:MessageParties>
public List<String> getRefs(String xmlMessageToSend)
{
    try
    {
        Document doc = createDocument(xmlMessageToSend.getBytes());
        XPath xpath = xPathFactory.newXPath();
        xpath.setNamespaceContext(new NamespaceContext() {

            @Override
            public String getNamespaceURI(String prefix)
            {
                if (prefix == null)
                    throw new NullPointerException("Null prefix");
                else if ("Env".equals(prefix))
                    return "http://www.om.com/schema/v1.0/envelope";
                else if ("BS".equals(prefix))
                    return "http://www.o.com/schema/v1.0/BusinessServices";

                return XMLConstants.NULL_NS_URI;
            }

            @Override
            public Iterator getPrefixes(String namespaceURI)
            {
                throw new UnsupportedOperationException();
            }

            @Override
            public String getPrefix(String namespaceURI)
            {
                throw new UnsupportedOperationException();
            }

        });
        XPathExpression exp = xpath
                .compile("/Message/MessageList/MessageDetail/Env:MessageContainer");
        Node result = (Node)exp.evaluate(doc, XPathConstants.NODE);
        System.out.println(result.getTextContent());
    }
    catch (XPathExpressionException | SAXException | IOException | ParserConfigurationException e)
    {
        e.printStackTrace();
    }

    return new ArrayList<String>();
}

3 个答案:

答案 0 :(得分:0)

您没有说出您用于浏览文档的内容,但通常情况下,API中应该有一种方法可以用来声明匹配的名称空间前缀Env上的那个:MessageContainer。然后,您可以在XPath中使用该前缀,例如//e:MessageContainer(假设您已将{&#39; e&#39;映射到"http://www.somesite.com/schema/v1.0/envelope")。

答案 1 :(得分:0)

您需要在XPath表达式中使用消息前缀。例如,

//foo:MessageContainer

此前缀不必与原始文档中使用的名称空间URI相同。在这里,我使用了前缀foo,即使它是您文档中的Env。只要两个前缀都映射到相同的URI(在此示例中为http://www.somesite.com/schema/v1.0/envelope),XPath就会匹配。

如何将此前缀绑定到所需的命名空间URI取决于嵌入XPath表达式的宿主语言。例如,在XSLT中,您只需在XSLT样式表中声明相关的前缀,就像在任何其他XML文档中一样。相反,在XOM中,您必须提供一个XPathContext对象,该对象相应地映射名称空间前缀。等等其他语言和API。

答案 2 :(得分:0)

您可以通过例如

访问您的元素
//Env:MessageContainer

但要实现这一目标,您的xmlns:Env="http://www.somesite.com/schema/v1.0/envelope" xmlns:BS="http://www.somesite.com/schema/v1.0/BusinessServices"应在<root>元素中定义,而不是<Env:MessageContainer>元素(或除此之外)。

但是如果你不能改变你的源XML,那么正确的解决方案就是编写与上面相同的综合风格:

//*[local-name()='MessageContainer'][namespace-uri()='http://www.somesite.com/schema/v1.0/envelope']