Java: come indentare XML generato da Transformer


112

Sto usando il trasformatore XML integrato di Java per prendere un documento DOM e stampare l'XML risultante. Il problema è che non fa affatto rientrare il testo nonostante abbia impostato esplicitamente il parametro "indent".

codice di esempio

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

 }
}

risultato

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

risultato desiderato

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

Pensieri?

Risposte:


215

È necessario abilitare "INDENT" e impostare l'importo del rientro per il trasformatore:

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

Aggiornare:


Riferimento: come rimuovere i nodi di testo solo spazi bianchi da un DOM prima della serializzazione?

(Mille grazie a tutti i membri in particolare @ marc-novakowski, @ james-murty e @saad) :


70
Mi sembra sciocco che il rientro predefinito sia 0, ma oltre a INDENT=yesho anche dovuto aggiungere questo:t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
lapo

1
Attenzione. Questa proprietà di indentazione non funziona in java 5. lo fa in java 7. Non ho provato in java 6
Hilikus

4
Se ci sono nodi interni che sono più linee, puoi far rientrare anche la parte interna? Il solo utilizzo di questo non fa rientrare i nodi interni.
eipark

1
@eipark con stackoverflow.com/a/979606/837530 , ho rimosso i spazi bianchi, e ora trattino come un fascino
Sa'ad

1
@lapo se il tuo provider è xalan (che probabilmente è se funziona), allora è disponibile comeorg.apache.xml.serializer.OutputPropertiesFactory.S_KEY_INDENT_AMOUNT
OrangeDog

21

Nessuna delle soluzioni suggerite ha funzionato per me. Quindi ho continuato a cercare una soluzione alternativa, che è finita per essere un misto delle due prima menzionate e un terzo passaggio.

  1. impostare il numero di rientro nella fabbrica del trasformatore
  2. abilitare la rientranza nel trasformatore
  3. avvolgere l'otuputstream con uno scrittore (o bufferwriter)
//(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"));

È necessario eseguire (3) per aggirare un comportamento "bacato" del codice di gestione xml.

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

(Se ho citato la mia fonte in modo errato, fatemelo sapere)


3
A cosa si riferisce "out" nell'ultima riga?
Mujimu

Hai bisogno di creare un nuovo numero intero usando un costruttore?
Benjineer

Immagino perché il tuo provider non è Xalan. Puoi controllare cosa sei TransformerFactoryrealmente in modo che gli altri lo sappiano.
OrangeDog

Il passaggio 3, utilizzando Writercome output, è essenziale.
erickson,

14

Il seguente codice funziona per me con Java 7. Ho impostato il rientro (sì) e il rientro (2) sul trasformatore (non la fabbrica del trasformatore) per farlo funzionare.

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 soluzione di @mabac per impostare l'attributo non ha funzionato per me, ma il commento di @ lapo si è rivelato utile.


8

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

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

Questa è una classe interna, quindi il tuo codice non sarà trasferibile su altre JVM (o anche più recenti).
OrangeDog

5

Se vuoi il rientro, devi specificarlo nel file TransformerFactory.

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

4

Ho usato la libreria Xerces (Apache) invece di scherzare con Transformer. Una volta aggiunta la libreria, aggiungi il codice qui sotto.

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

Sì. Ho provato tutti gli altri approcci con il Transformer ma tutti rotti. L'intera libreria W3C è un disastro. Xerces ha funzionato.
Sintonizzabile

3

Per me l'aggiunta ha DOCTYPE_PUBLICfunzionato:

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, "sì"); è la chiave
silentsudo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.