1

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?

Cormac90
  • 23
  • 1
  • 3
  • Correct me if I'm wrong but your usage of `local-name()` will not retrieve anything since in your example there is no **node** with that name. If you want to extract the **attribute** of the `Party` node (which is what I assume you want to do) then you could use something like `//Party[@PartyID][1]` (which in your example will return `123456789`), you can change the number `[1]` to specify which `Party` node you want to access. – Ceiling Gecko Jan 14 '14 at 14:24

2 Answers2

1

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)

StuartLC
  • 104,537
  • 17
  • 209
  • 285
0

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

Community
  • 1
  • 1
Amir Katz
  • 1,027
  • 1
  • 10
  • 24
  • Correct, except that technically the stuff inside the CDATA is not XML. It would be XML if it weren't inside CDATA; CDATA means "character data", and its only purpose is to say "the stuff in here might look like XML, but don't be fooled, it's just plain characters.". So ideally, you wouldn't put it in CDATA if you want to treat it as XML. – Michael Kay Jan 14 '14 at 23:17