Search code examples
javaxmlmoxy

Marshalling and Unmarshalling changes xml using moxy


I am trying to create this kind(xsd inside) of documents. some examples are here. Because of constant values in root-element and some other constant elements i generated a template with eclipse:

<?xml version="1.0" encoding="UTF-8"?>
<invoice:response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:invoice="http://www.forum-datenaustausch.ch/invoice" xmlns="http://www.forum-datenaustausch.ch/invoice" xsi:schemaLocation="http://www.forum-datenaustausch.ch/invoice generalInvoiceResponse_440.xsd" language="de">
  <invoice:processing>
    <invoice:transport from="" to="">
      <invoice:via sequence_id="0" via=""/>
    </invoice:transport>
  </invoice:processing>
  <invoice:payload response_timestamp="0">
    <invoice:invoice request_date="2001-12-31T12:00:00" request_id="" request_timestamp="0"/>
  </invoice:payload>
</invoice:response>

But simple unmarshalling and marshalling changes the content:

<?xml version="1.0" encoding="UTF-8"?>
<response xmlns="http://www.forum-datenaustausch.ch/invoice" xmlns:ns1="http://www.w3.org/2000/09/xmldsig#" xmlns:ns0="http://www.w3.org/2001/04/xmlenc#" language="de">
   <processing>
      <transport from="" to="">
         <via via="" sequence_id="0"/>
      </transport>
   </processing>
   <payload response_timestamp="0">
      <invoice request_timestamp="0" request_date="2001-12-31T12:00:00.0" request_id=""/>
   </payload>
</response>

for some reason the schema location attribute is gone. this could be added manually before marshalling. the 2nd problem is, all prefixes are gone. i don't know who consumes the produced xml (do they unmarshal with handwritten code? with or without validation?). Because of this i want an output that is most similar to given examples and valid. So is there either a way to leave existing elements and attributes untouched and to let moxy add namespace prefixes to each element?


Solution

  • The following should help. This question is also being handled on the EclipseLink forum:


    for some reason the schema location attribute is gone.

    You can specify the following property on the Marshaller to output a schema location:

    marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.forum-datenaustausch.ch/invoice generalInvoiceResponse_440.xsd");
    

    2nd problem is, all prefixes are gone.

    The namespace prefixes are gone, but the namespace qualification is the same (all elements have the same local name and namespace URI). In the first document the invoice prefix is assigned to the http://www.forum-datenaustausch.ch/invoice namespace, and in the second document that namespace is assigned as the default namespace


    CONTROLLING NAMESPACE PREFIXES AT DESIGN TIME

    You can provide MOXy hints at what namespace prefixes should be used by leveraging the @XmlSchema annotation (see: http://blog.bdoughan.com/2011/11/jaxb-and-namespace-prefixes.html).

    package-info

    @XmlSchema(
        elementFormDefault=XmlNsForm.QUALIFIED,
        namespace="http://www.forum-datenaustausch.ch/invoice",
        xmlns={
            @XmlNs(prefix="invoice", namespaceURI="http://www.forum-datenaustausch.ch/invoice"),
            @XmlNs(prefix="ds", namespaceURI="http://www.w3.org/2000/09/xmldsig#"),
            @XmlNs(prefix="xenc", namespaceURI="http://www.w3.org/2001/04/xmlenc#")
        }
    )
    package forum16559889;
    
    import javax.xml.bind.annotation.*;
    

    Response

    package forum16559889;
    
    import javax.xml.bind.annotation.XmlRootElement;
    
    @XmlRootElement
    public class Response {
    }
    

    Demo

    package forum16559889;
    
    import javax.xml.bind.*;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jc = JAXBContext.newInstance(Response.class);
    
            Response response = new Response();
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.forum-datenaustausch.ch/invoice generalInvoiceResponse_440.xsd");
            marshaller.marshal(response, System.out);
        }
    
    }
    

    Output

    <?xml version="1.0" encoding="UTF-8"?>
    <invoice:response xsi:schemaLocation="http://www.forum-datenaustausch.ch/invoice generalInvoiceResponse_440.xsd" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:invoice="http://www.forum-datenaustausch.ch/invoice" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
    

    CONTROLLING THE NAMESPACE PREFIXES AT RUNTIME

    You cam leverage MOXy's NamespacePrefixMapper extension to control the namespace prefixes used at runtime.

    package forum16559889;
    
    import javax.xml.bind.*;
    import org.eclipse.persistence.jaxb.MarshallerProperties;
    import org.eclipse.persistence.oxm.NamespacePrefixMapper;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jc = JAXBContext.newInstance(Response.class);
    
            Response response = new Response();
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.forum-datenaustausch.ch/invoice generalInvoiceResponse_440.xsd");
    
            marshaller.setProperty(MarshallerProperties.NAMESPACE_PREFIX_MAPPER, new NamespacePrefixMapper() {
    
                @Override
                public String getPreferredPrefix(String namespaceUri,
                        String suggestion, boolean requirePrefix) {
                    if("http://www.forum-datenaustausch.ch/invoice".equals(namespaceUri)) {
                        return "invoice";
                    } else if("http://www.w3.org/2000/09/xmldsig#".equals(namespaceUri)) {
                        return "ds";
                    } else if("http://www.w3.org/2001/04/xmlenc#".equals(namespaceUri)) {
                        return "xenc";
                    } else {
                        return null;
                    }
                }
    
            });
    
            marshaller.marshal(response, System.out);
        }
    
    }