質問

I am trying to extract a 'PartyID' from a request using XPath. This request is in the form of XML.

Here is the 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>

I have a method in my java code called getPartyId(). This method should extract the PartyID from the XML. However I cannot get this method to return the PartyID no matter what XPath query I use, this is where I need help.

Here is the getPartyId method:

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;
    }

I believe that the problem lies with the XPathExpression:

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

I have tried a number of alternatives for 'expr' however none of these have worked. Has anyone got any ideas?

役に立ちましたか?

解決

Because the xml you need to parse is sitting inside a CDATA block, you'll need to re-parse the value of s1:arg0 before accessing data within it.

You will need to do this in 2 steps

  • You will need to access the arg0 node in the http://rules.kmtool.abc.com namespace.

Since you don't have a NamespaceContext for this inner xmlns, you can use :

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

  • You then need to load this value into another InputSource. The PartyId attribute can be accessed via the path:

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

(no need to use local-name() since there aren't any xmlns in the CDATA)

他のヒント

Notice that your inner xml is inside CDATA node. So basiclly you are trying to query path of an XML inside CDATA.

As this thread state Xpath to the tag inside CDATA

Seems this is not possible :(

I would suggest take the CData inside the code and parse it into a new XML Document and query that.

Thanks, Amir

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top