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?

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) :


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)


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.


8

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

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

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();

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

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");

transformer.setOutputProperty (OutputKeys.DOCTYPE_PUBLIC, "oui"); est la clé
silentsudo
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.