Search code examples
javasoapcdatasaaj

How to replace (&lt;) with (<) in soap response in Java SAAJ


I have a soap response that contains CDATA, but I process the response in java all the opening quotations (<)in are replaced with (<).

Here is how the response should look Like

 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
  <ns:Response xmlns:ns="http://pipeline_ws">
     <ns:return>
     <![CDATA[<fr><Result>
        <ListPartner>
            <operator>
                <country_code></country_code>
                <currency_code></currency_code>
                <operator_code></operator_code>

        </operator>
     </ListPartner>
 </Result></fr>]]></ns:return>
  </ns:Response>
</soapenv:Body>
</soapenv:Envelope>

But Instead This is the Response That Am getting

 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
    <ns:Response xmlns:ns="http://pipeline_ws">
        <ns:return>
&lt;fr>
&lt;Result>
&lt;ListPartner>
&lt;operator>
&lt;country_code>&lt;/country_code>
&lt;currency_code>&lt;/currency_code>
&lt;operator_code>&lt;/operator_code>   
&lt;/operator>
&lt;/ListPartner>
&lt;/Result>
&lt;/fr>
    </ns:return>
</ns:Response>
</soapenv:Body>
</soapenv:Envelope>

Please help in providing a solution to remove/replace the unwanted characters(<) so I can parse the response. I am using SAAJ to process the response

        // Process the SOAP Response
SOAPMessage soapResponse = soapConnection.call(createSOAPRequest(), url);
        soapResponse.writeTo(System.out);

Solution

  • Parse the XML and retrieve the text node value of <ns:return/> as a string. Then this string can be treated itself as XML.

    final XPath xpath = XPathFactory.newInstance().newXPath();
    xpath.setNamespaceContext(new MyNamespaceContext());
    final String xmlFile = "1.xml";
    final InputSource source = new InputSource(new FileInputStream(xmlFile));
    
    final DocumentBuilderFactory fac = DocumentBuilderFactory.newInstance();
    fac.setNamespaceAware(true);
    final Document doc = fac.newDocumentBuilder().parse(source);
    
    final String result = (String) xpath.evaluate(
        "/soapenv:Envelope/soapenv:Body/pipeline:Response/pipeline:return/text()", 
        doc, XPathConstants.STRING);
    
    System.out.println(result);
    

    Beware that you should set namespace awareness in the DocumentBuilderFactory instance.

    And here a simple NamespaceContext implementation defining the needed namespace prefixes:

    static class MyNamespaceContext implements NamespaceContext {
    
      private Map<String, String> ns;
    
      public MyNamespaceContext() {
        ns = new HashMap<String, String>();
        ns.put("xs", "http://www.w3.org/2001/XMLSchema");
        ns.put("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
        ns.put("pipeline", "http://pipeline_ws");
      }
    
      public String getNamespaceURI(String prefix) {
        return ns.get(prefix);
      }
    
      public Iterator<String> getPrefixes() {
        return ns.keySet().iterator();
      }
    
      public Iterator<String> getPrefixes(String namespaceURI) {
        final List<String> prefixes = new LinkedList<String>();
        if(namespaceURI != null) {
          for(Entry<String, String> entry: ns.entrySet()) {
            if(namespaceURI.equals(entry.getValue())) {
              prefixes.add(entry.getKey());
            }
          }
        }
        return prefixes.iterator();
      }
    
      public Map<String, String> getPrefixMapping() {
        return ns;
      }
    
      @Override
      public String getPrefix(String namespaceURI) {
        if(namespaceURI != null) {
          for(Entry<String, String> entry: ns.entrySet()) {
            if(namespaceURI.equals(entry.getValue())) {
              return entry.getKey();
            }
          }
        }
        return null;
      }    
    }
    

    The output for the first XML version is:

    <fr><Result>
       <ListPartner>
            <operator>
                <country_code></country_code>
                <currency_code></currency_code>
                <operator_code></operator_code>
    
        </operator>
     </ListPartner>
    </Result></fr>
    

    And for the second:

    <fr>
    <Result>
    <ListPartner>
    <operator>
    <country_code></country_code>
    <currency_code></currency_code>
    <operator_code></operator_code>   
    </operator>
    </ListPartner>
    </Result>
    </fr>