Java: Jak wciskać kod XML generowany przez Transformer


112

Używam wbudowanego w Javę transformatora XML, aby wziąć dokument DOM i wydrukować wynikowy XML. Problem polega na tym, że w ogóle nie wcina się tekstu, pomimo jawnego ustawienia parametru „indent”.

przykładowy kod

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

 }
}

wynik

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

pożądany rezultat

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

Myśli?

Odpowiedzi:


215

Musisz włączyć „WCIĘCIE” i ustawić wielkość wcięcia dla transformatora:

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

Aktualizacja:


Odniesienie: Jak usunąć węzły tekstowe zawierające tylko białe znaki z DOM przed serializacją?

(Podziękowania dla wszystkich członków, zwłaszcza @ marc-novakowski, @ james-murty i @saad) :


70
Wydaje mi się głupie, że domyślne wcięcie to 0, ale oprócz tego INDENT=yesmusiałem też dodać to:t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
— lapo

1
Strzec się. Ta nieruchomość wcięcie nie działa w Javie 5. robi w Javie 7. Nie próbowałem w Java 6
— Hilikus

4
Jeśli istnieją węzły wewnętrzne składające się z wielu linii, czy możesz również wciąć część wewnętrzną? Samo użycie tego nie powoduje wcięcia węzłów wewnętrznych.
— eipark

1
@eipark with stackoverflow.com/a/979606/837530 , usunąłem spacje, a teraz wcięcia jak urok
— Sa'ad

1
@lapo, jeśli twoim dostawcą jest xalan (co prawdopodobnie jest, jeśli to działa), to jest dostępne jakoorg.apache.xml.serializer.OutputPropertiesFactory.S_KEY_INDENT_AMOUNT
— OrangeDog

21

Żadne z sugerowanych rozwiązań nie zadziałało. Kontynuowałem więc poszukiwanie alternatywnego rozwiązania, które okazało się połączeniem dwóch wcześniej wspomnianych i trzeciego kroku.

  1. ustaw numer wcięcia w transformerfactory
  2. włącz wcięcie w transformatorze
  3. zawiń otuputstream pisarzem (lub buforowanym pisarzem)
//(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"));

Musisz (3) obejść "błędne" zachowanie kodu obsługującego XML.

Źródło: johnnymac75 @ http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6296446

(Jeśli nieprawidłowo zacytowałem moje źródło, daj mi znać)


3
Do czego odnosi się „out” w ostatniej linii?
— mujimu

Czy musisz utworzyć nową liczbę całkowitą za pomocą konstruktora?
— Benjineer,

Zgaduję, ponieważ twoim dostawcą nie jest Xalan. Czy możesz sprawdzić, czym TransformerFactorywłaściwie jest, aby inni wiedzieli.
— OrangeDog

Krok 3, użycie Writerjako wyjścia, jest niezbędny.
— erickson

14

Poniższy kod działa dla mnie z Javą 7. Ustawiłem wcięcie (tak) i wielkość wcięcia (2) na transformatorze (nie fabryce transformatorów), aby działał.

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

Rozwiązanie @ mabac do ustawiania atrybutu nie działało w moim przypadku, ale komentarz @ lapo okazał się pomocny.


8

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

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

Jest to klasa wewnętrzna, więc Twój kod nie będzie przenośny na inne (lub nawet nowsze) maszyny JVM.
— OrangeDog

5

Jeśli chcesz wcięcia, musisz określić je jako TransformerFactory.

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

4

Użyłem biblioteki Xerces (Apache) zamiast bawić się Transformerem. Po dodaniu biblioteki dodaj poniższy kod.

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

Tak. Wypróbowałem wszystkie inne podejścia z Transformerem, ale wszystkie się zepsuły. Cała biblioteka W3C to bałagan. Xerces działał.
— Tuntable

3

U mnie dodanie DOCTYPE_PUBLICzadziałało:

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, "tak"); jest kluczem
— silentsudo
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.