Java: Einrücken von XML, das von Transformer generiert wurde


111

Ich verwende den in Java integrierten XML-Transformator, um ein DOM-Dokument zu erstellen und das resultierende XML auszudrucken. Das Problem ist, dass der Text überhaupt nicht eingerückt wird, obwohl der Parameter "Einzug" explizit festgelegt wurde.

Beispielcode

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

 }
}

Ergebnis

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

erwünschtes Ergebnis

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

Gedanken?

Antworten:


214

Sie müssen 'INDENT' aktivieren und den Einrückungsbetrag für den Transformator einstellen:

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

Aktualisieren:


Referenz: Wie werden vor der Serialisierung nur Leerzeichen-Textknoten aus einem DOM entfernt?

(Vielen Dank an alle Mitglieder, insbesondere an @ marc-novakowski, @ james-murty und @saad) :


70
Scheint mir albern, dass die Standardeinrückung 0 ist, aber zusätzlich musste INDENT=yesich auch t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
Folgendes

1
In acht nehmen. Diese Einrückungseigenschaft funktioniert nicht in Java 5. Sie funktioniert in Java 7. Ich habe es nicht in Java 6 versucht
Hilikus

4
Wenn es innere Knoten gibt, die aus mehreren Linien bestehen, können Sie auch den inneren Teil einrücken? Wenn Sie dies nur verwenden, werden die inneren Knoten nicht eingerückt.
Eipark

1
@eipark mit stackoverflow.com/a/979606/837530 , ich habe die Leerzeichen entfernt und jetzt Einrückungen wie ein Zauber
Sa'ad

1
@ Lapo Wenn Ihr Provider Xalan ist (was es wahrscheinlich ist, wenn dies funktioniert), dann ist es verfügbar alsorg.apache.xml.serializer.OutputPropertiesFactory.S_KEY_INDENT_AMOUNT
OrangeDog

21

Keine der vorgeschlagenen Lösungen hat bei mir funktioniert. Also suchte ich weiter nach einer alternativen Lösung, die eine Mischung aus beiden zuvor genannten und einem dritten Schritt war.

  1. Setzen Sie die Einrückungsnummer in die Transformatorfabrik
  2. Aktivieren Sie den Einzug im Transformator
  3. Wickeln Sie den Otuputstream mit einem Writer (oder gepufferten Writer) ein.
//(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"));

Sie müssen (3) ausführen, um ein "fehlerhaftes" Verhalten des XML-Verarbeitungscodes zu umgehen.

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

(Wenn ich meine Quelle falsch zitiert habe, lassen Sie es mich bitte wissen.)


3
Worauf bezieht sich "out" in der letzten Zeile?
Mujimu

Müssen Sie mit einem Konstruktor eine neue Ganzzahl erstellen?
Benjineer

Ich vermute, weil Ihr Provider nicht Xalan ist. Können Sie überprüfen, was Sie TransformerFactorytatsächlich sind, damit andere es wissen?
OrangeDog

Schritt 3, bei dem a Writerals Ausgabe verwendet wird, ist unerlässlich.
Erickson

14

Der folgende Code funktioniert für mich mit Java 7. Ich habe den Einzug (Ja) und den Einrückungsbetrag (2) am Transformator (nicht in der Transformatorfabrik) festgelegt, damit er funktioniert.

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

Die Lösung von @ mabac zum Festlegen des Attributs funktionierte bei mir nicht, aber der Kommentar von @ lapo erwies sich als hilfreich.


8

importieren Sie com.sun.org.apache.xml.internal.serializer.OutputPropertiesFactory

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

Dies ist eine interne Klasse, sodass Ihr Code nicht auf andere (oder sogar neuere) JVMs portierbar ist.
OrangeDog

5

Wenn Sie die Einrückung möchten, müssen Sie sie für das angeben TransformerFactory.

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

4

Ich habe die Xerces (Apache) -Bibliothek verwendet, anstatt mit Transformer herumzuspielen. Sobald Sie die Bibliothek hinzugefügt haben, fügen Sie den folgenden Code hinzu.

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

Ja. Ich habe alle anderen Ansätze mit dem Transformer ausprobiert, aber alle sind kaputt. Die gesamte W3C-Bibliothek ist ein Chaos. Xerces hat funktioniert.
Tuntable

3

Für mich hat das Hinzufügen DOCTYPE_PUBLICfunktioniert:

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, "yes"); ist der Schlüssel
Silentsudo
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.