web-dev-qa-db-fra.com

Comment marshaler sans espace de noms?

J'ai un XML répétitif assez grand à créer en utilisant JAXB. Stocker l'objet entier dans la mémoire puis faire le marshaling prend trop de mémoire. Essentiellement, mon XML ressemble à ceci:

<Store>
  <item />
  <item />
  <item />
.....
</Store>

Actuellement, ma solution au problème consiste à "coder en dur" la balise racine dans un flux de sortie et à rassembler chacun des éléments répétitifs un par un:

aOutputStream.write("<?xml version="1.0"?>")
aOutputStream.write("<Store>")

foreach items as item
  aMarshaller.marshall(item, aOutputStream)
end
aOutputStream.write("</Store>")
aOutputStream.close()

D'une certaine manière, la JAXB génère le XML comme ceci

 <Store  xmlns="http://stackoverflow.com">
  <item xmlns="http://stackoverflow.com"/>
  <item xmlns="http://stackoverflow.com"/>
  <item xmlns="http://stackoverflow.com"/>
.....
</Store>

Bien qu'il s'agisse d'un XML valide, mais il semble tout simplement laid, je me demande donc s'il existe un moyen de dire au marshaller de ne pas mettre d'espace de noms pour les éléments de l'élément? Ou existe-t-il une meilleure façon d'utiliser JAXB pour sérialiser en XML morceau par morceau?

19
Alvin

Ce qui suit a fait l'affaire pour moi:

         XMLStreamWriter writer = ...
         writer.setNamespaceContext(new NamespaceContext() {
            public Iterator getPrefixes(String namespaceURI) {
                return null;
            }

            public String getPrefix(String namespaceURI) {
                return "";
            }

            public String getNamespaceURI(String prefix) {
                return null;
            }
        });
8
Tamas Kornai

Vérifier votre package-info.Java (dans le package où se trouvent vos classes annotées jaxb). Il y a l'attribut namespace de @XmlSchema Là.

De plus, il existe un attribut namespace dans le @XmlRootElement annotation.

12
Bozho

Il existe un moyen très simple de se débarrasser des préfixes d'espace de noms dans votre cas: définissez simplement l'attribut elementFormDefault sur non qualifié dans votre schéma, comme ceci:

<xs:schema attributeFormDefault="unqualified" elementFormDefault="unqualified"
       xmlns:xs="http://www.w3.org/2001/XMLSchema"
       xmlns:your="http://www.stackoverflow.com/your/namespace">

Vous obtiendrez le préfixe d'espace de noms uniquement dans la première balise:

<ns1:your xmlns:ns1="http://www.stackoverflow.com/your/namespace">

J'espère que ça aide.

Cordialement Pawel Procaj

7
MrShinobi

J'ai essayé toutes les solutions fournies comme réponses ici et aucune d'entre elles n'a fonctionné pour mon environnement. Mes exigences actuelles sont:

  1. jdk1.6.0_45
  2. Les classes annotées JAXB sont générées à chaque reconstruction, donc leur modification n'est pas une option.

Je voudrais partager avec vous les résultats de mes expériences avec les solutions que j'ai trouvées sur stackoverflow.

Contexte d'espace de noms personnalisé lien

Solution simple et élégante, mais dans mon environnement, j'ai une exception avec le stacktrace suivant:

javax.xml.stream.XMLStreamException: Trying to write END_DOCUMENT when document has no root (ie. trying to output empty document).

at com.ctc.wstx.sw.BaseStreamWriter.throwOutputError(BaseStreamWriter.Java:1473)
at com.ctc.wstx.sw.BaseStreamWriter.reportNwfStructure(BaseStreamWriter.Java:1502)
at com.ctc.wstx.sw.BaseStreamWriter.finishDocument(BaseStreamWriter.Java:1663)
at com.ctc.wstx.sw.BaseStreamWriter.close(BaseStreamWriter.Java:288)
at MyDataConverter.marshal(MyDataConverter.Java:53)

Je suis resté coincé en essayant de comprendre pourquoi cette exception se produit et j'ai décidé d'essayer autre chose.

Modification de package-info.Java lien

La solution la plus simple que j'ai trouvée. Cela fonctionne généralement, mais ce fichier est généré à chaque génération. C'est pourquoi je dois trouver une autre solution.

Modification du schéma lien

Fonctionne comme décrit mais ne résout pas mon problème. J'ai toujours un espace de noms dans l'élément racine.

DélégationXMLStreamWriter lien

J'ai également essayé les solutions mentionnées ici, mais j'ai eu une affirmation étrange dans com.Sun.xml.bind.v2.runtime.output.NamespaceContextImpl (méthode declareNsUri) que je n'ai pas réussi à vaincre.

Ma solution

Lors de la recherche du problème avec assertion, j'ai dû implémenter ma propre version de XMLStreamWriter basée sur DelegatingXMLStreamWriter.Java

public class NamespaceStrippingXMLStreamWriter extends DelegatingXMLStreamWriter {

  public NamespaceStrippingXMLStreamWriter(XMLStreamWriter xmlWriter) throws XMLStreamException {
    super(xmlWriter);
  }

  @Override
  public void writeNamespace(String prefix, String uri) throws XMLStreamException {
    // intentionally doing nothing
  }

  @Override
  public void writeDefaultNamespace(String uri) throws XMLStreamException {
    // intentionally doing nothing
  }

  @Override
  public void writeStartElement(String prefix, String local, String uri) throws XMLStreamException {
    super.writeStartElement(null, local, null);
  }

  @Override
  public void writeStartElement(String uri, String local) throws XMLStreamException {
    super.writeStartElement(null, local);
  }

  @Override
  public void writeEmptyElement(String uri, String local) throws XMLStreamException {
    super.writeEmptyElement(null, local);
  }

  @Override
  public void writeEmptyElement(String prefix, String local, String uri) throws XMLStreamException {
    super.writeEmptyElement(null, local, null);
  }

  @Override
  public void writeAttribute(String prefix, String uri, String local, String value) throws XMLStreamException {
    super.writeAttribute(null, null, local, value);
  }

  @Override
  public void writeAttribute(String uri, String local, String value) throws XMLStreamException {
    super.writeAttribute(null, local, value);
  }
}

L'idée principale est d'éviter de transmettre des informations d'espace de noms au XMLStreamWriter sous-jacent. J'espère que cela vous aidera à gagner du temps pour résoudre un problème similaire.

PS. Il n'est pas nécessaire d'étendre DelegatingXMLStreamWriter dans votre code. J'ai fait cela pour montrer quelles méthodes doivent être modifiées.

6
sergio

Pour moi, le simple fait d'appeler xmlStreamWriter.setDefaultNamespace("") a résolu le problème.

Une autre chose à laquelle vous devez faire attention pour supprimer le préfixe d'espace de noms de la sortie est que partout où vous avez @XmlElement, assurez-vous qu'il n'inclut pas la propriété d'espace de noms comme @XmlElement(name="", namespace"http://..."); sinon, aucune des solutions ne fonctionnera.

2
HamedKhan

Si vous ne spécifiez pas d'espace de noms, JaxB n'en écrira pas.

Vous pourriez utiliser Stax sur un Stream, si votre structure n'est pas trop compliquée.

0
tkr