How to transform an XML Object in the specified format?

3

I would like to generate XML for a request that I will make in Java from an object. The XML I want to generate is as follows:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<v:Envelope xmlns:v="http://schemas.xmlsoap.org/soap/envelope/">
  <v:Header>
    <b>LGE Nexus 5</b>
    <j></j>
    <i>-2574.2675703366904</i>
    <c>ANDROID</c>
    <d>6.0.1</d>
    <e>4.1.5</e>
    <f>127.0.0.1</f>
    <g>79f7bfca9d83085965c523eefc267339d61abb8f</g>
    <k>1702a351-0c04-47c1-a785-486118238872</k>
    <h>-4703.798004479785</h>
    <l>2017-08-08 15:42:39</l>
    <m>8797e74f0d6eb7b1ff3dc114d4aa12d3</m>
  </v:Header>
  <v:Body>
    <n0:getStatus xmlns:n0="http://soap.ws.placa.service.sinesp.serpro.gov.br/">
      <a>ABC123</a>
    </n0:getStatus>
  </v:Body>
</v:Envelope>

The class I am currently using is as follows:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import org.w3c.dom.Document;

/**
 *
 * @author Lucas Souza [[email protected]]
 */
@XmlRootElement
public class Request {

  private String plate;

  private String device;
  private double latitude;
  private String operationalSystem;
  private String majorVersion;
  private String minorVersion;
  private String ip;
  private String token;
  private String uuid;
  private double longitude;
  private String date;
  private String hash;

  public Request() {
    this.device = "LGE Nexus 5";
    this.operationalSystem = "ANDROID";
    this.majorVersion = "6.0.1";
    this.minorVersion = "4.1.5";
    this.ip = "127.0.0.1";
    this.hash = "8797e74f0d6eb7b1ff3dc114d4aa12d3";
  }

  @XmlElement(name = "a")
  public String getPlate() {
    return plate;
  }

  public void setPlate(String plate) {
    this.plate = plate;
  }

  @XmlTransient
  public String getDevice() {
    return device;
  }

  public void setDevice(String device) {
    this.device = device;
  }

  @XmlTransient
  public double getLatitude() {
    return latitude;
  }

  public void setLatitude(double latitude) {
    this.latitude = latitude;
  }

  @XmlTransient
  public String getOperationalSystem() {
    return operationalSystem;
  }

  public void setOperationalSystem(String operationalSystem) {
    this.operationalSystem = operationalSystem;
  }

  @XmlTransient
  public String getMajorVersion() {
    return majorVersion;
  }

  public void setMajorVersion(String majorVersion) {
    this.majorVersion = majorVersion;
  }

  @XmlTransient
  public String getMinorVersion() {
    return minorVersion;
  }

  public void setMinorVersion(String minorVersion) {
    this.minorVersion = minorVersion;
  }

  @XmlTransient
  public String getIp() {
    return ip;
  }

  public void setIp(String ip) {
    this.ip = ip;
  }

  @XmlTransient
  public String getToken() {
    return token;
  }

  public void setToken(String token) {
    this.token = token;
  }

  @XmlTransient
  public String getUuid() {
    return uuid;
  }

  public void setUuid(String uuid) {
    this.uuid = uuid;
  }

  @XmlTransient
  public double getLongitude() {
    return longitude;
  }

  public void setLongitude(double longitude) {
    this.longitude = longitude;
  }

  @XmlTransient
  public String getDate() {
    return date;
  }

  public void setDate(String date) {
    this.date = date;
  }

  @XmlTransient
  public String getHash() {
    return hash;
  }

  public void setHash(String hash) {
    this.hash = hash;
  }

  public String toXML() throws JAXBException, ParserConfigurationException, SOAPException, IOException {
    Document document;
    Marshaller marshaller;
    SOAPMessage soapMessage;
    ByteArrayOutputStream outputStream;
    String output;

    document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
    marshaller = JAXBContext.newInstance(Request.class).createMarshaller();
    marshaller.marshal(this, document);
    soapMessage = MessageFactory.newInstance().createMessage();
    soapMessage.getSOAPBody().addDocument(document);
    this.fillHeaders(soapMessage.getSOAPHeader());
    outputStream = new ByteArrayOutputStream();
    soapMessage.writeTo(outputStream);
    output = new String(outputStream.toByteArray());

    return output;
  }

  private void fillHeaders(SOAPHeader soapHeader) throws SOAPException {
    soapHeader.setAttribute("b", this.device);
    soapHeader.setAttribute("i", String.valueOf(this.latitude));
    soapHeader.setAttribute("c", this.operationalSystem);
    soapHeader.setAttribute("d", this.majorVersion);
    soapHeader.setAttribute("e", this.minorVersion);
    soapHeader.setAttribute("f", this.ip);
    soapHeader.setAttribute("g", this.token);
    soapHeader.setAttribute("k", this.uuid);
    soapHeader.setAttribute("h", String.valueOf(this.longitude));
    soapHeader.setAttribute("l", this.date);
    soapHeader.setAttribute("m", this.hash);
  }
}

But the XML I'm having in return using the Result#toXML method is as follows:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header b="LGE Nexus 5" c="ANDROID" d="6.0.1" e="4.1.5" f="127.0.0.1" g="79f7bfca9d83085965c523eefc267339d61abb8f" h="605.0793837821" i="142.74057974918404" k="84f4a062-3cca-42f0-9dd6-262efe5a5d4f" l="2017-08-08 15:50:38" m="8797e74f0d6eb7b1ff3dc114d4aa12d3" />
    <SOAP-ENV:Body>
        <request>
            <a>ABC123</a>
        </request>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

How can I set up my object and perform toXML in the correct way, best and reproduce XML as specified?

Basically what I see in the difference between the formats is:

  • % created%;
  • Prefix Envelope in v ;
  • Elements in tags ;
  • Method name in Header ;
  • Attribute Body in call;
asked by anonymous 08.08.2017 / 20:53

2 answers

1

I used the SOAPHeader.addHeaderElement to create the elements that would be needed in the header. After that I did the treatment as String , after all namespace is mandatory in certain elements. The final code of the class was as follows:

import java.io.ByteArrayOutputStream;
import java.util.Iterator;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;

/**
 *
 * @author Lucas Souza [[email protected]]
 */
@XmlRootElement(name = "getStatus", namespace = "http://soap.ws.placa.service.sinesp.serpro.gov.br/")
public class Request {

  private final String prefix = "v";

  private String plate;

  private String device;
  private Double latitude;
  private String operationalSystem;
  private String majorVersion;
  private String minorVersion;
  private String ip;
  private String token;
  private String uuid;
  private Double longitude;
  private String date;
  private String hash;

  public Request() {
    this.device = "LGE Nexus 5";
    this.operationalSystem = "ANDROID";
    this.majorVersion = "6.0.1";
    this.minorVersion = "4.1.5";
    this.ip = "127.0.0.1";
    this.hash = "8797e74f0d6eb7b1ff3dc114d4aa12d3";
  }

  @XmlElement(name = "a")
  public String getPlate() {
    return plate;
  }

  public void setPlate(String plate) {
    this.plate = plate;
  }

  @XmlTransient
  public String getDevice() {
    return device;
  }

  public void setDevice(String device) {
    this.device = device;
  }

  @XmlTransient
  public Double getLatitude() {
    return latitude;
  }

  public void setLatitude(Double latitude) {
    this.latitude = latitude;
  }

  @XmlTransient
  public String getOperationalSystem() {
    return operationalSystem;
  }

  public void setOperationalSystem(String operationalSystem) {
    this.operationalSystem = operationalSystem;
  }

  @XmlTransient
  public String getMajorVersion() {
    return majorVersion;
  }

  public void setMajorVersion(String majorVersion) {
    this.majorVersion = majorVersion;
  }

  @XmlTransient
  public String getMinorVersion() {
    return minorVersion;
  }

  public void setMinorVersion(String minorVersion) {
    this.minorVersion = minorVersion;
  }

  @XmlTransient
  public String getIp() {
    return ip;
  }

  public void setIp(String ip) {
    this.ip = ip;
  }

  @XmlTransient
  public String getToken() {
    return token;
  }

  public void setToken(String token) {
    this.token = token;
  }

  @XmlTransient
  public String getUuid() {
    return uuid;
  }

  public void setUuid(String uuid) {
    this.uuid = uuid;
  }

  @XmlTransient
  public Double getLongitude() {
    return longitude;
  }

  public void setLongitude(Double longitude) {
    this.longitude = longitude;
  }

  @XmlTransient
  public String getDate() {
    return date;
  }

  public void setDate(String date) {
    this.date = date;
  }

  @XmlTransient
  public String getHash() {
    return hash;
  }

  public void setHash(String hash) {
    this.hash = hash;
  }

  public String toXML() {
    Transformer transformer;
    Document document;
    Marshaller marshaller;
    SOAPMessage soapMessage;
    ByteArrayOutputStream outputStream;
    StreamResult result;
    String output;

    try {
      document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
      marshaller = JAXBContext.newInstance(Request.class).createMarshaller();
      marshaller.marshal(this, document);
      soapMessage = MessageFactory.newInstance().createMessage();
      transformer = TransformerFactory.newInstance().newTransformer();
      transformer.setOutputProperty(OutputKeys.INDENT, "yes");
      transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
      transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
      this.fillEnvelope(soapMessage.getSOAPPart().getEnvelope());
      this.fillBody(soapMessage.getSOAPBody(), document);
      this.fillHeader(soapMessage.getSOAPHeader());
      outputStream = new ByteArrayOutputStream();
      result = new StreamResult(outputStream);
      transformer.transform(soapMessage.getSOAPPart().getContent(), result);
      output = outputStream.toString();
      output = fillXMLString(output);
    } catch (JAXBException | ParserConfigurationException | SOAPException | TransformerException ex) {
      throw new RuntimeException(ex);
    }

    return output;
  }

  private void fillEnvelope(SOAPEnvelope envelope) {
    Iterator prefixes;
    envelope.setPrefix(this.prefix);

    prefixes = envelope.getNamespacePrefixes();

    while (prefixes.hasNext()) {
      String currentPrefix = (String) prefixes.next();

      envelope.removeNamespaceDeclaration(currentPrefix);
    }
  }

  private void fillHeader(SOAPHeader soapHeader) throws SOAPException {
    soapHeader.setPrefix(this.prefix);

    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "b")).setValue(this.device);
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "c")).setValue(this.operationalSystem);
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "d")).setValue(this.majorVersion);
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "e")).setValue(this.minorVersion);
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "f")).setValue(this.ip);
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "g")).setValue(this.token);
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "h")).setValue(String.valueOf(this.longitude));
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "i")).setValue(String.valueOf(this.latitude));
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "j")).setValue("");
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "k")).setValue(this.uuid);
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "l")).setValue(this.date);
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "m")).setValue(this.hash);
  }

  private String fillXMLString(String xml) {
    xml = xml.replace(" xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\"", "");

    return xml;
  }

  private void fillBody(SOAPBody soapBody, Document document) throws SOAPException {
    soapBody.addDocument(document);
    soapBody.setPrefix(this.prefix);
  }
}

And the result was:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<v:Envelope xmlns:v="http://schemas.xmlsoap.org/soap/envelope/">
  <v:Header>
    <b>LGE Nexus 5</b>
    <j/>
    <i>-2574.2675703366904</i>
    <c>ANDROID</c>
    <d>6.0.1</d>
    <e>4.1.5</e>
    <f>127.0.0.1</f>
    <g>79f7bfca9d83085965c523eefc267339d61abb8f</g>
    <k>1702a351-0c04-47c1-a785-486118238872</k>
    <h>-4703.798004479785</h>
    <l>2017-08-08 15:42:39</l>
    <m>8797e74f0d6eb7b1ff3dc114d4aa12d3</m>
  </v:Header>
  <v:Body>
    <ns2:getStatus xmlns:ns2="http://soap.ws.placa.service.sinesp.serpro.gov.br/">
      <a>ABC123</a>
    </ns2:getStatus>
  </v:Body>
</v:Envelope>
    
17.08.2017 / 14:29
3

I use JAXBContext to generate the XMLs. Here is an example conversion to XML;

public static String toXml(Object object) throws JAXBException {
    JAXBContext context = JAXBContext.newInstance(object.getClass());
    Marshaller m = context.createMarshaller();
    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); // formata o xml
    m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE); // Retirar tag inicial
    StringWriter sw = new StringWriter();
    m.marshal(object, sw);
    String xmlString = sw.toString();

    return xmlString;
}

For the attributes to be given the correct name in generation I use the following annotations:

@XmlRootElement(name = "soapenv:Envelope")
@XmlAccessorType(XmlAccessType.FIELD)
public class SoapenvEnvelope implements Serializable {

    private static final long serialVersionUID = 1L;

    @XmlAttribute(name = "xmlns:soapenv")
    private String xmlnsSoapenv;

    @XmlAttribute(name = "xmlns:geop")
    private String xmlnsGeop;

    @XmlElement(name = "soapenv:Header")
    private String soapenvHeader = "";

Being @XmlAttribute the attributes that will go inside the tag and @XmlElement identifies the attributes of the entity.

    
08.08.2017 / 22:16