Remove namespace prefix while JAXB marshalling

前端 未结 5 1821
無奈伤痛
無奈伤痛 2020-11-29 05:45

I have JAXB objects created from a schema. While marshalling, the xml elements are getting annotated with ns2. I have tried all the options that exist over the net for this

相关标签:
5条回答
  • 2020-11-29 06:21

    You can let the namespaces be written only once. You will need a proxy class of the XMLStreamWriter and a package-info.java. Then you will do in your code:

    StringWriter stringWriter = new StringWriter();
    XMLStreamWriter writer = new Wrapper((XMLStreamWriter) XMLOutputFactory
                                                                   .newInstance().createXMLStreamWriter(stringWriter));
    JAXBContext jaxbContext = JAXBContext.newInstance(Collection.class);
    Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
    jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
    jaxbMarshaller.marshal(books, writer);
    System.out.println(stringWriter.toString());
    

    Proxy class (the important method is "writeNamespace"):

                class WrapperXMLStreamWriter implements XMLStreamWriter {
    
                       private final XMLStreamWriter writer;
    
                       public WrapperXMLStreamWriter(XMLStreamWriter writer) {
                           this.writer = writer;
                       }
    
                         //keeps track of what namespaces were used so that not to 
                         //write them more than once
                       private List<String> namespaces = new ArrayList<String>();
    
                       public void init(){
                           namespaces.clear();
                       }
    
                       public void writeStartElement(String localName) throws XMLStreamException {
                           init();
                           writer.writeStartElement(localName);
    
                       }
    
                       public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException {
                           init();
                           writer.writeStartElement(namespaceURI, localName);
                       }
    
                       public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
                           init();
                           writer.writeStartElement(prefix, localName, namespaceURI);
                       }
    
                       public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException {
                           if(namespaces.contains(namespaceURI)){ 
                               return;
                           }
                           namespaces.add(namespaceURI);
                           writer.writeNamespace(prefix, namespaceURI);
                       }
    
        // .. other delegation method, always the same pattern: writer.method() ...
    
    }
    

    package-info.java:

    @XmlSchema(elementFormDefault=XmlNsForm.QUALIFIED, attributeFormDefault=XmlNsForm.UNQUALIFIED ,
            xmlns = { 
            @XmlNs(namespaceURI = "http://www.w3.org/2001/XMLSchema-instance", prefix = "xsi")})
    package your.package;
    
    import javax.xml.bind.annotation.XmlNs;
    import javax.xml.bind.annotation.XmlNsForm;
    import javax.xml.bind.annotation.XmlSchema;
    
    0 讨论(0)
  • 2020-11-29 06:29

    You can use the NamespacePrefixMapper extension to control the namespace prefixes for your use case. The same extension is supported by both the JAXB reference implementation and EclipseLink JAXB (MOXy).

    • http://wiki.eclipse.org/EclipseLink/Release/2.4.0/JAXB_RI_Extensions/Namespace_Prefix_Mapper
    0 讨论(0)
  • 2020-11-29 06:30

    After much research and tinkering I have finally managed to achieve a solution to this problem. Please accept my apologies for not posting links to the original references - there are many and I wasn't taking notes - but this one was certainly useful.

    My solution uses a filtering XMLStreamWriter which applies an empty namespace context.

    public class NoNamesWriter extends DelegatingXMLStreamWriter {
    
      private static final NamespaceContext emptyNamespaceContext = new NamespaceContext() {
    
        @Override
        public String getNamespaceURI(String prefix) {
          return "";
        }
    
        @Override
        public String getPrefix(String namespaceURI) {
          return "";
        }
    
        @Override
        public Iterator getPrefixes(String namespaceURI) {
          return null;
        }
    
      };
    
      public static XMLStreamWriter filter(Writer writer) throws XMLStreamException {
        return new NoNamesWriter(XMLOutputFactory.newInstance().createXMLStreamWriter(writer));
      }
    
      public NoNamesWriter(XMLStreamWriter writer) {
        super(writer);
      }
    
      @Override
      public NamespaceContext getNamespaceContext() {
        return emptyNamespaceContext;
      }
    
    }
    

    You can find a DelegatingXMLStreamWriter here.

    You can then filter the marshalling xml with:

      // Filter the output to remove namespaces.
      m.marshal(it, NoNamesWriter.filter(writer));
    

    I am sure there are more efficient mechanisms but I know this one works.

    0 讨论(0)
  • 2020-11-29 06:35

    For me, only changing the package-info.java class worked like a charm, exactly as zatziky stated :

    package-info.java

     @javax.xml.bind.annotation.XmlSchema
     (namespace = "http://example.com",
     xmlns = {@XmlNs(prefix = "", namespaceURI = "http://example.com")},
     elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
    
    package my.package;
    import javax.xml.bind.annotation.XmlNs;
    
    0 讨论(0)
  • 2020-11-29 06:40

    I got the working result by the setting the property:

    marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "");
    
    0 讨论(0)
提交回复
热议问题