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.