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?
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;
}
});
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.
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
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:
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.
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.
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.