Java: Bagaimana Indentasi XML yang Dihasilkan oleh Transformer

112

Saya menggunakan transformator XML bawaan Java untuk mengambil dokumen DOM dan mencetak XML yang dihasilkan. Masalahnya adalah bahwa teks sama sekali tidak menjorok ke dalam meskipun telah menyetel parameter "indentasi" secara eksplisit.

Kode sampel

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

 }
}

hasil

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

hasil yang diinginkan

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

Pikiran?

Mike
sumber

Jawaban:

215

Anda perlu mengaktifkan 'INDENT' dan menyetel jumlah indentasi untuk transformator:

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

Memperbarui:


Referensi: Bagaimana cara menghapus node teks khusus spasi dari DOM sebelum serialisasi?

(Banyak terima kasih kepada semua anggota terutama @ marc-novakowski, @ james-murty dan @saad) :

adatapost
sumber
70
Tampak konyol bagi saya bahwa lekukan default adalah 0, tetapi selain itu INDENT=yessaya juga harus menambahkan ini:t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
lapo
1
Awas. Properti indentasi ini tidak berfungsi di java 5. ia berfungsi di java 7. Belum mencoba di java 6
Hilikus
4
Jika ada node dalam yang terdiri dari beberapa baris, dapatkah Anda membuat indentasi bagian dalamnya juga? Hanya menggunakan ini tidak mengindentasi node bagian dalam.
eipark
1
@eipark dengan stackoverflow.com/a/979606/837530 , saya menghapus spasi, dan sekarang indentasi seperti pesona
Sa'ad
1
@lapo jika penyedia Anda adalah xalan (yang mungkin jika ini berfungsi), maka tersedia sebagaiorg.apache.xml.serializer.OutputPropertiesFactory.S_KEY_INDENT_AMOUNT
OrangeDog
21

Tak satu pun dari solusi yang disarankan berhasil untuk saya. Jadi saya terus mencari solusi alternatif, yang akhirnya menjadi campuran dari dua langkah sebelumnya dan langkah ketiga.

  1. atur nomor indentasi ke dalam pabrik transformator
  2. aktifkan indentasi pada transformator
  3. membungkus otuputstream dengan penulis (atau penulis buffered)
//(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"));

Anda harus melakukan (3) untuk mengatasi perilaku "buggy" dari kode penanganan xml.

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

(Jika saya salah mengutip sumber saya, beri tahu saya)

mabac
sumber
3
Apa yang dimaksud dengan "keluar" di baris terakhir?
mujimu
Apakah Anda perlu membuat integer baru menggunakan konstruktor?
Benjineer
Saya menebak karena penyedia Anda bukan Xalan. Bisakah Anda memeriksa apa Anda TransformerFactorysebenarnya sehingga orang lain tahu.
OrangeDog
Langkah 3, menggunakan a Writersebagai output, sangat penting.
erickson
14

Kode berikut berfungsi untuk saya dengan Java 7. Saya mengatur indentasi (ya) dan jumlah indentasi (2) pada trafo (bukan pabrik trafo) untuk membuatnya berfungsi.

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

Solusi @ mabac untuk menyetel atribut tidak berhasil untuk saya, tetapi komentar @ lapo terbukti membantu.

remipod
sumber
8

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

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

sumber
Ini adalah kelas internal, jadi kode Anda tidak akan portabel ke JVM lain (atau bahkan yang lebih baru).
OrangeDog
5

Jika Anda menginginkan indentasi, Anda harus menentukannya ke TransformerFactory.

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

Saya menggunakan perpustakaan Xerces (Apache) daripada mengotak-atik Transformer. Setelah Anda menambahkan perpustakaan, tambahkan kode di bawah ini.

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);
tujuh
sumber
Iya. Saya mencoba semua pendekatan lain dengan Transformer tetapi semuanya rusak. Seluruh perpustakaan W3C berantakan. Xerces bekerja.
Tuntable
3

Bagi saya menambahkan DOCTYPE_PUBLICberhasil:

transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,"yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "10");
Vikas Chowdhury
sumber
transformer.setOutputProperty (OutputKeys.DOCTYPE_PUBLIC, "yes"); adalah kuncinya
silentsudo