Java: как сделать отступ в XML, созданном Transformer


112

Я использую встроенный в Java преобразователь XML, чтобы взять документ DOM и распечатать полученный XML. Проблема в том, что он вообще не делает отступ для текста, несмотря на явную установку параметра «indent».

образец кода

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
Что означает "out" в последней строке?
mujimu

Вам нужно создать новое целое число с помощью конструктора?
Benjineer

Я предполагаю, потому что ваш провайдер не Ксалан. Можете ли вы проверить, что вы на TransformerFactoryсамом деле, чтобы другие знали.
OrangeDog

Шаг 3 с использованием a в Writerкачестве вывода очень важен.
Эриксон

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 в беспорядке. Xerces работал.
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, «да»); is the key
Silentsudo 08
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.