web-dev-qa-db-fra.com

Supprimer le préfixe d'espace de noms lors du marshaling JAXB

J'ai des objets JAXB créés à partir d'un schéma. Pendant le marshaling, les éléments xml sont annotés avec ns2. J'ai essayé toutes les options qui existent sur le net pour ce problème, mais aucune ne fonctionne. Je ne peux pas modifier mon schéma ou changer package-info.Java. Veuillez aider

21
user2487308

Après beaucoup de recherches et de bricolage, j'ai finalement réussi à trouver une solution à ce problème. Veuillez accepter mes excuses pour ne pas avoir publié de liens vers les références originales - il y en a beaucoup et je ne prenais pas de notes - mais this one était certainement utile.

Ma solution utilise un filtrage XMLStreamWriter qui applique un contexte d'espace de noms vide.

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;
  }

}

Vous pouvez trouver un DelegatingXMLStreamWriterici .

Vous pouvez ensuite filtrer le XML de marshaling avec:

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

Je suis sûr qu'il existe des mécanismes plus efficaces mais je sais que celui-ci fonctionne.

18
OldCurmudgeon

Pour moi, changer uniquement la classe package-info.Java a fonctionné comme un charme, exactement comme l'a déclaré zatziky:

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;
13
cata2d

Vous ne pouvez laisser les espaces de noms écrits qu'une seule fois. Vous aurez besoin d'une classe proxy de XMLStreamWriter et d'un package-info.Java. Ensuite, vous ferez dans votre 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());

Classe proxy (la méthode importante est "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;
5
Amio.io

Vous pouvez utiliser l'extension NamespacePrefixMapper pour contrôler les préfixes d'espace de noms pour votre cas d'utilisation. La même extension est prise en charge à la fois par l'implémentation de référence JAXB et par EclipseLink JAXB (MOXy).

3
bdoughan