Java: comment indenter le XML généré par Transformer

112

J'utilise le transformateur XML intégré de Java pour prendre un document DOM et imprimer le XML résultant. Le problème est qu'il ne met pas du tout le texte en retrait malgré la définition explicite du paramètre "indent".

exemple de code

public class TestXML {

 public static void main(String args[]) throws Exception {
  ByteArrayOutputStream s;

  Document d = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
  Transformer t = TransformerFactory.newInstance().newTransformer();

  Element a,b;

  a = d.createElement("a");
  b = d.createElement("b");

  a.appendChild(b);

  d.appendChild(a);

  t.setParameter(OutputKeys.INDENT, "yes");

  s = new ByteArrayOutputStream();

  t.transform(new DOMSource(d),new StreamResult(s));

  System.out.println(new String(s.toByteArray()));

 }
}

résultat

<?xml version="1.0" encoding="UTF-8" standalone="no"?><a><b/></a>

résultat désiré

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<a>
 <b/>
</a>

Pensées?

Mike
la source

Réponses:

215

Vous devez activer 'INDENT' et définir le montant de retrait pour le transformateur:

t.setOutputProperty(OutputKeys.INDENT, "yes");
t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");

Mettre à jour:


Référence: Comment supprimer des nœuds de texte contenant uniquement des espaces blancs d'un DOM avant la sérialisation?

(Un grand merci à tous les membres en particulier @ marc-novakowski, @ james-murty et @saad) :

adatapost
la source
70
Cela me semble idiot que l'indentation par défaut soit 0, mais en plus de cela, INDENT=yesj'ai également dû ajouter ceci:t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
lapo
1
Il faut se méfier. Cette propriété d'indentation ne fonctionne pas en java 5. elle fonctionne en java 7. Je n'ai pas essayé en java 6
Hilikus
4
S'il y a des nœuds internes composés de plusieurs lignes, pouvez-vous également indenter la partie interne? Le simple fait d'utiliser ceci n'indente pas les nœuds internes.
eipark
1
@eipark avec stackoverflow.com/a/979606/837530 , j'ai supprimé les espaces, et maintenant les retraits comme un charme
Sa'ad
1
@lapo si votre fournisseur est xalan (ce qui est probablement le cas si cela fonctionne), alors il est disponible en tant queorg.apache.xml.serializer.OutputPropertiesFactory.S_KEY_INDENT_AMOUNT
OrangeDog
21

Aucune des solutions suggérées n'a fonctionné pour moi. J'ai donc continué à chercher une solution alternative, qui a fini par être un mélange des deux mentionnés précédemment et une troisième étape.

  1. définir le numéro d'indentation dans le transformerfactory
  2. activer le retrait dans le transformateur
  3. envelopper l'otuputstream avec un écrivain (ou un rédacteur en mémoire tampon)
//(1)
TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute("indent-number", new Integer(2));

//(2)
Transformer t = tf.newTransformer();
t.setOutputProperty(OutputKeys.INDENT, "yes");

//(3)
t.transform(new DOMSource(doc),
new StreamResult(new OutputStreamWriter(out, "utf-8"));

Vous devez faire (3) pour contourner un comportement "bogué" du code de gestion xml.

Source: johnnymac75 @ http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6296446

(Si j'ai mal cité ma source, merci de me le faire savoir)

mabac
la source
3
À quoi fait référence «out» dans la dernière ligne?
mujimu
Avez-vous besoin de créer un nouvel entier à l'aide d'un constructeur?
Benjineer
Je suppose que votre fournisseur n'est pas Xalan. Pouvez-vous vérifier ce que vous êtes TransformerFactoryréellement pour que les autres le sachent.
OrangeDog
L'étape 3, en utilisant une Writercomme sortie, est essentielle.
erickson le
14

Le code suivant fonctionne pour moi avec Java 7. J'ai défini l'indentation (oui) et l'indent-amount (2) sur le transformateur (pas l'usine de transformateurs) pour le faire fonctionner.

TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
t.setOutputProperty(OutputKeys.INDENT, "yes");
t.transform(source, result);

La solution de @ mabac pour définir l'attribut n'a pas fonctionné pour moi, mais le commentaire de @ lapo s'est avéré utile.

remipod
la source
8

import com.sun.org.apache.xml.internal.serializer.OutputPropertiesFactory

transformer.setOutputProperty(OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, "2");

la source
Il s'agit d'une classe interne, donc votre code ne sera pas portable vers d'autres JVM (ou même plus récents).
OrangeDog
5

Si vous voulez l'indentation, vous devez le spécifier dans le fichier TransformerFactory.

TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute("indent-number", new Integer(2));
Transformer t = tf.newTransformer();
Lucbelanger
la source
4

J'ai utilisé la bibliothèque Xerces (Apache) au lieu de jouer avec Transformer. Une fois que vous avez ajouté la bibliothèque, ajoutez le code ci-dessous.

OutputFormat format = new OutputFormat(document);
format.setLineWidth(65);
format.setIndenting(true);
format.setIndent(2);
Writer outxml = new FileWriter(new File("out.xml"));
XMLSerializer serializer = new XMLSerializer(outxml, format);
serializer.serialize(document);
sept sept
la source
Oui. J'ai essayé toutes les autres approches avec le Transformer mais toutes cassées. Toute la bibliothèque du W3C est en désordre. Xerces a travaillé.
Tuntable
3

Pour moi, l'ajout a DOCTYPE_PUBLICfonctionné:

transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,"yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "10");
Vikas Chowdhury
la source
transformer.setOutputProperty (OutputKeys.DOCTYPE_PUBLIC, "oui"); est la clé
silentsudo