Search code examples
javasoapxpathjxpath

JXPath to filter SOAP message


I'm trying to extract the value of the node GoodEmail from a SOAP response. It seems that no matter what I try, I always get a org.apache.commons.jxpath.JXPathNotFoundException.

SOAP response:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
      <VerifyEmailResponse xmlns="http://ws.cdyne.com/">
         <VerifyEmailResult>
            <ResponseText>Invalid Email Address</ResponseText>
            <ResponseCode>0</ResponseCode>
            <LastMailServer/>
            <GoodEmail>false</GoodEmail>
         </VerifyEmailResult>
      </VerifyEmailResponse>
   </soap:Body>
</soap:Envelope>

The Java code:

String payload = message.getPayloadAsString(); //The SOAP response
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db =  dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(payload));

Document doc = db.parse(is);
JXPathContext context = JXPathContext.newContext(doc);
String jxpathReply = (String) context.getValue("//soap:Envelope/soap:Body/VerifyEmailResponse/VerifyEmailResult/GoodEmail");

To me it seems that the error code suggest that it is the xpath filter that is wrong. I've tried a few different, but can't get it right. What am I doing wrong?


Solution

  • This is the most FAQ in XPath. Search for "xpath default namespace" and you'll find many good answers.

    A brief explanation is that in XPath any unprefixed name is considered to belong to "no namespace". Therefore, if we want to specify the names of elements that belong to some namespace (including a default namesopace), these names must be prefixed and the prefix specified must be associated (using the particular XPath engine API) withthe namespace-uri of the namespace, in which the particular node resides.

    Therefore, the expression could be something like this:

    /soap:Envelope/soap:Body/x:VerifyEmailResponse/x:VerifyEmailResult/x:GoodEmail
    

    where the prefix "x" is associated (by "registering" this namespace association) with the namespace "http://ws.cdyne.com/"