Ява: Як відступити XML, сформований трансформатором


112

Я використовую вбудований в трансформатор XML Java, щоб взяти документ DOM і роздрукувати отриманий XML. Проблема полягає в тому, що він взагалі не відступає тексту, незважаючи на те, що явно встановив параметр "відступ".

зразок коду

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

 }
}

результат

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

бажаний результат

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

Думки?

Відповіді:


215

Вам потрібно ввімкнути «INDENT» і встановити кількість відступу для трансформатора:

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

Оновлення:


Довідка: Як зняти текстові вузли, що містять лише пробіли, з DOM перед серіалізацією?

(Велике спасибі всім членам, особливо @ marc-novakowski, @ james-murty та @saad) :


70
Мені здається нерозумним, що відступ за замовчуванням дорівнює 0, але крім цього INDENT=yesя також повинен був додати це:t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
lapo

1
Остерігайся. Цей властивість відступу не працює у java 5. це у java 7. Не пробували у java 6
Hilikus

4
Якщо є внутрішні вузли, які є кількома лініями, чи можете ви також відступити внутрішню частину? Просто використання цього не відступає від внутрішніх вузлів.
eipark

1
@eipark з stackoverflow.com/a/979606/837530 , я видалив пробільні, і тепер відступи як шарм
Саад

1
@lapo якщо ваш провайдер - xalan (що, мабуть, так і є, якщо це працює), він доступний якorg.apache.xml.serializer.OutputPropertiesFactory.S_KEY_INDENT_AMOUNT
OrangeDog

21

Жодне із запропонованих рішень не працювало для мене. Тож я продовжував шукати альтернативне рішення, яке в результаті стало сумішшю двох раніше згаданих та третього кроку.

  1. встановити відступ-номер у трансформатор
  2. включити відступ в трансформаторі
  3. оберніть otuputstream з автором (або буферизатором)
//(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"));

Ви повинні зробити (3), щоб вирішити "баггі" поведінку коду обробки XML.

Джерело: johnnymac75 @ http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6296446

(Якщо я неправильно цитував своє джерело, будь ласка, повідомте мене про це)


3
На що посилається "поза" в останньому рядку?
mujimu

Чи потрібно створити нове ціле число за допомогою конструктора?
Benjineer

Я здогадуюсь, тому що ваш постачальник не Xalan. Чи можете ви перевірити, що TransformerFactoryє насправді, щоб інші знали.
OrangeDog

Крок 3, використовуючи Writerяк вихід, є важливим.
erickson

14

Наступний код працює для мене з Java 7. Я встановлюю відступ (так) і відступ (2) на трансформаторі (а не на заводі трансформаторів), щоб він працював.

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

Рішення @ mabac щодо встановлення атрибута не спрацювало для мене, але коментар @ lapo виявився корисним.


8

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

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

Це внутрішній клас, тому ваш код не буде переносним для інших (або навіть новіших) JVM.
OrangeDog

5

Якщо ви хочете відступ, потрібно вказати його на TransformerFactory.

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

4

Я використовував бібліотеку Xerces (Apache) замість того, щоб возитися з Transformer. Після додавання бібліотеки додайте код нижче.

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

Так. Я спробував усі інші підходи з Трансформатором, але всі зламали. Вся бібліотека W3C - це безлад. Ксерс працював.
Tuntable

3

Для мене додавання DOCTYPE_PUBLICпрацювало:

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, "так"); є ключовим
silentsudo
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.