【问题标题】:XPATH won't workXPATH 不起作用
【发布时间】:2014-01-14 13:56:12
【问题描述】:

我正在尝试使用 XPath 从请求中提取“PartyID”。此请求采用 XML 格式。

这是 XML:

<?xml version="1.0" encoding="UTF-8"?>
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"     xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<s1:invokerules xmlns:s1="http://rules.kmtool.abc.com"><s1:arg0><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
   <kbdInitiateRequest>
    <kmTestHeader>
        <MessageId>USER1_MSG1</MessageId>
            <TestDate>08/07/2008 07:34:15</TestDate>
            <TestReference>
            <ConductorReference>
                <InvokeIdentifier>
                    <RefNum>USER1_Ref1</RefNum>
                </InvokeIdentifier>
            </ConductorReference>
        </TestReference>
        <TestParty>
            <ConductorParty>
                <Party PartyID="123456789" AgencyID="DUNS">
                    <TestContact>
                        <DetailedContact>
                                                <ContactName>Michael Jackson</ContactName>
                            <Telephone>02071059053</Telephone>
                            <TelephoneExtension>4777</TelephoneExtension>
                            <Email>Michal.Jackson@Neverland.com</Email>
                            <Title>Mr</Title>
                            <FirstName>Michael</FirstName>
                            <Initials>MJ</Initials>
                        </DetailedContact>
                    </TestContact>
                </Party>
            </ConductorParty>
            <PerformerParty>
                <Party PartyID="987654321" AgencyID="DUNS">
                </Party>
            </PerformerParty>
        </TestParty>
    </kmTestHeader>
    <kmToolMessage>
        <controlNode>
            <userRequest>INITIATE</userRequest>
        </controlNode>
        <customer>
            <circuitID>000111333777</circuitID>
    </customer>
</kmToolMessage> 
</kbdInitiateRequest>

]]></s1:arg0>
</s1:invokerules>
</soapenv:Body>
</soapenv:Envelope>

我的 java 代码中有一个名为 getPartyId() 的方法。此方法应从 XML 中提取 PartyID。但是,无论我使用什么 XPath 查询,我都无法让这个方法返回 PartyID,这就是我需要帮助的地方。

这里是 getPartyId 方法:

private String getPartyId(String xml) throws XPathExpressionException
    {       
        XPathFactory xPathfactory = XPathFactory.newInstance();
        XPath xpath = xPathfactory.newXPath();      
        xpath.setNamespaceContext(new NamespaceContext() {
            public String getNamespaceURI(String prefix) {
                if (prefix == null) throw new NullPointerException("Null prefix");
                else if ("SOAP-ENV".equals(prefix)) return "http://schemas.xmlsoap.org/soap/envelope/";
                else if ("xml".equals(prefix)) return XMLConstants.XML_NS_URI;
                return XMLConstants.NULL_NS_URI;
            }

            public String getPrefix(String uri) {
                throw new UnsupportedOperationException();
            }

            public Iterator getPrefixes(String uri) {
                throw new UnsupportedOperationException();
            }
        });

        XPathExpression expr = xpath.compile("/SOAP-ENV:Envelope/SOAP-ENV:Body/*/*/*/*/*/*/*/*/*/*/*[local-name()='PartyID']/text()");

        InputSource source = new InputSource(new StringReader(xml));

        String dunsId = (String) expr.evaluate(source,XPathConstants.STRING);

        return dunsId;
    }

我认为问题在于 XPathExpression:

XPathExpression expr = xpath.compile("/SOAP-ENV:Envelope/SOAP-ENV:Body/*/*/*/*/*/*/*/*/*/*/*[local-name()='PartyID']/text()");

我已经尝试了许多“expr”的替代方案,但是这些都没有奏效。有人有什么想法吗?

【问题讨论】:

  • 如果我错了,请纠正我,但您对 local-name() 的使用不会检索到任何内容,因为在您的示例中没有具有该名称的 node。如果您想提取 Party 节点的 属性 (这是我假设您想要做的),那么您可以使用类似 //Party[@PartyID][1] 的东西(在您的示例中将返回 123456789 ),您可以更改编号[1] 以指定您要访问的Party 节点。

标签: java xml xpath xml-namespaces


【解决方案1】:

因为您需要解析的xml 位于CDATA 块内,所以您需要在访问其中的数据之前重新解析s1:arg0 的值。

您需要分两步完成此操作

  • 您需要访问http://rules.kmtool.abc.com 命名空间中的arg0 节点。

由于您没有此内部 xmlns 的 NamespaceContext,您可以使用:

/SOAP-ENV:Envelope/SOAP-ENV:Body/*[local-name()='invokerules'] /*[local-name()='arg0']/text()

  • 然后您需要将此值加载到另一个InputSourcePartyId 属性可以通过路径访问:

kbdInitiateRequest/kmTestHeader/TestParty/ConductorParty/Party/@PartyID

(无需使用local-name(),因为CDATA 中没有任何xmlns

【讨论】:

    【解决方案2】:

    请注意,您的内部 xml 位于 CDATA 节点内。 所以基本上你正在尝试在 CDATA 中查询 XML 的路径。

    作为这个线程状态 Xpath to the tag inside CDATA

    看来这是不可能的:(

    我建议将代码中的 CData 解析为新的 XML 文档并进行查询。

    谢谢, 阿米尔

    【讨论】:

    • 正确,但从技术上讲,CDATA 中的内容不是 XML。如果它不在 CDATA 中,它将是 XML; CDATA 意思是“字符数据”,它的唯一目的是说“这里的东西可能看起来像 XML,但不要被愚弄,它只是普通字符。”。所以理想情况下,如果你想把它当作 XML,你不会把它放在 CDATA 中。
    猜你喜欢
    • 2018-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-30
    • 2012-09-08
    • 2014-04-21
    • 1970-01-01
    相关资源
    最近更新 更多