Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unmarshall SOAP response using JAXB if namespace declaration is on SOAP envelope?

Tags:

JAXB can only unmarshall an XML if the soap envelope has already been removed. However, the SOAP response I'm trying to unmarshall has its namespace declaration on the soap envelope. If I remove the soap envelope, the namespace declaration will also be removed. As such the prefix of the tags will be referring to none. This causes JAXB to throw an error. How can I unmarshall a SOAP response using JAXB if the namespace is declared on the SOAP envelope?

A similar sample of the XML that I need to unmarshall is below:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://example.com/">     <soapenv:Body>         <ns:getNumberResponse>             <number>123456789</number>         </ns:getNumberResponse>     </soapenv:Body> </soapenv:Envelope> 

This is what happens if I remove the soap envelope:

<ns:getNumberResponse>     <number>123456789</number> </ns:getNumberResponse> 

If I removed the soap envelope, the namespace declaration will also be gone. JAXB won't be able to unmarshall the above xml because the namespace definition for the prefix "ns" is missing. As such it will return a "The prefix "ns" for element "ns:getNumberResponse" is not bound." error message. How do I fix it?

Please note that I'm using JDK 1.5. I'm not sure if there is a way to solve this in JDK 1.6. I was able to use JAXB because I downloaded the required jars for using JAXB.

like image 879
Arci Avatar asked Jul 13 '12 07:07

Arci


People also ask

How to unmarshal SOAP XML to Java object?

You need to extract the content from the Envelope first, you can do this with message. getSOAPBody(). extractContentAsDocument() if you create a SOAPMessage object from your content first.

How to create SOAP envelope in Java?

SOAPEnvelope envelope = soapPart. getEnvelope(); You can now use the getHeader and getBody methods of envelope to retrieve its empty SOAPHeader and SOAPBody objects. SOAPHeader header = envelope.

What is SOAP envelope XML?

A SOAP message is an ordinary XML document containing the following elements: An Envelope element that identifies the XML document as a SOAP message. A Header element that contains header information. A Body element that contains call and response information.


2 Answers

You can use a StAX parser to parse the SOAP message and then advance the XMLStreamReader to the getNumberResponse element and use the unmarshal method that takes a class parameter. A StAX parser is included in Java SE 6, but you will need to download one for Java SE 5. Woodstox is a popular StAX parser.

Response

package forum11465653;  public class Response {      private long number;      public long getNumber() {         return number;     }      public void setNumber(long number) {         this.number = number;     }  } 

Demo

An XMLStreamReader has a NamespaceContext. The NamespaceContext knows all the active namespace declarations for the current level. Your JAXB (JSR-222) implementation will be able to leverage this to get the necessary information.

package forum11465653;  import java.io.FileReader; import javax.xml.bind.*; import javax.xml.stream.*;  public class Demo {      public static void main(String[] args) throws Exception{         XMLInputFactory xif = XMLInputFactory.newFactory();         XMLStreamReader xsr = xif.createXMLStreamReader(new FileReader("src/forum11465653/input.xml"));         xsr.nextTag(); // Advance to Envelope tag         xsr.nextTag(); // Advance to Body tag         xsr.nextTag(); // Advance to getNumberResponse tag         System.out.println(xsr.getNamespaceContext().getNamespaceURI("ns"));          JAXBContext jc = JAXBContext.newInstance(Response.class);         Unmarshaller unmarshaller = jc.createUnmarshaller();         JAXBElement<Response> je = unmarshaller.unmarshal(xsr, Response.class);         System.out.println(je.getName());         System.out.println(je.getValue());     }  } 

Output

http://example.com/ {http://example.com/}getNumberResponse forum11465653.Response@781f6226 
like image 52
bdoughan Avatar answered Oct 15 '22 13:10

bdoughan


You could parse the whole SOAP message using a DOM parser, which would be able to resolve all the namespaces at parse time. Then extract the element you require from the resulting DOM tree and pass that to the unmarshaller.

DomDemo

package forum11465653;  import java.io.File; import javax.xml.bind.*; import javax.xml.parsers.*; import javax.xml.transform.dom.DOMSource; import org.w3c.dom.*;  public class DomDemo {      public static void main(String[] args) throws Exception{         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();         dbf.setNamespaceAware(true);         DocumentBuilder db = dbf.newDocumentBuilder();         Document d = db.parse(new File("src/forum11465653/input.xml"));         Node getNumberResponseElt = d.getElementsByTagNameNS("http://example.com/", "getNumberResponse").item(0);          JAXBContext jc = JAXBContext.newInstance(Response.class);         Unmarshaller unmarshaller = jc.createUnmarshaller();         JAXBElement<Response> je = unmarshaller.unmarshal(new DOMSource(getNumberResponseElt), Response.class);         System.out.println(je.getName());         System.out.println(je.getValue());     }  } 

Output

{http://example.com/}getNumberResponse forum11465653.Response@19632847 
like image 35
Ian Roberts Avatar answered Oct 15 '22 14:10

Ian Roberts