Симпатичный вывод на печать из javax.xml.transform.Transformer только со стандартным java api (позиционирование отступов и Doctype)

Используя следующий простой код:

package test;

import java.io.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;

public class TestOutputKeys {
    public static void main(String[] args) throws TransformerException {

        // Instantiate transformer input
        Source xmlInput = new StreamSource(new StringReader(
                "<!-- Document comment --><aaa><bbb/><ccc/></aaa>"));
        StreamResult xmlOutput = new StreamResult(new StringWriter());

        // Configure transformer
        Transformer transformer = TransformerFactory.newInstance()
                .newTransformer(); // An identity transformer
        transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "testing.dtd");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.transform(xmlInput, xmlOutput);

        System.out.println(xmlOutput.getWriter().toString());
    }

}

Я получаю вывод:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Document comment --><!DOCTYPE aaa SYSTEM "testing.dtd">

<aaa>
<bbb/>
<ccc/>
</aaa>

Вопрос A: тег doctype появляется после комментария к документу. Можно ли сделать так, чтобы оно появилось до комментария к документу?

Вопрос B: Как добиться отступов, используя только API JavaSE 5.0? Этот вопрос по сути идентичен тому, как печатать xml из java, но почти все ответы на этот вопрос зависят от внешних библиотек. Единственный применимый ответ (опубликованный пользователем по имени Lorenzo Boccaccia), который использует только API Java, в основном равен приведенному выше коду, но не работает для меня (как показано в выводе, я не получаю отступов).

Я предполагаю, что вы должны установить количество пробелов для отступа, как это делают многие ответы с внешними библиотеками, но я просто не могу найти, где указать это в Java API. Учитывая тот факт, что в java api существует возможность установить для свойства отступа значение "yes", должна быть возможность выполнить отступ каким-либо образом. Я просто не могу понять, как.

4 ответа

Недостающая часть - это сумма отступа. Вы можете установить отступ и сумму отступа следующим образом:

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

Небольшой класс утилит в качестве примера...

import org.apache.xml.serialize.XMLSerializer;

public class XmlUtil {

public static Document file2Document(File file) throws Exception {
    if (file == null || !file.exists()) {
        throw new IllegalArgumentException("File must exist![" + file == null ? "NULL"
                : ("Could not be found: " + file.getAbsolutePath()) + "]");
    }
    DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
    dbFactory.setNamespaceAware(true);
    return dbFactory.newDocumentBuilder().parse(new FileInputStream(file));
}

public static Document string2Document(String xml) throws Exception {
    InputSource src = new InputSource(new StringReader(xml));
    DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
    dbFactory.setNamespaceAware(true);
    return dbFactory.newDocumentBuilder().parse(src);
}

public static OutputFormat getPrettyPrintFormat() {
    OutputFormat format = new OutputFormat();
    format.setLineWidth(120);
    format.setIndenting(true);
    format.setIndent(2);
    format.setEncoding("UTF-8");
    return format;
}

public static String document2String(Document doc, OutputFormat format) throws Exception {
    StringWriter stringOut = new StringWriter();
    XMLSerializer serial = new XMLSerializer(stringOut, format);
    serial.serialize(doc);
    return stringOut.toString();
}

public static String document2String(Document doc) throws Exception {
    return XmlUtil.document2String(doc, XmlUtil.getPrettyPrintFormat());
}

public static void document2File(Document doc, File file) throws Exception {
    XmlUtil.document2String(doc, XmlUtil.getPrettyPrintFormat());
}

public static void document2File(Document doc, File file, OutputFormat format) throws Exception {
    XMLSerializer serializer = new XMLSerializer(new FileOutputStream(file), format);
    serializer.serialize(doc);
}
}

XMLserializer предоставляется xercesImpl от Apache Foundation. Вот maven зависимость:

<dependency>
    <groupId>xerces</groupId>
    <artifactId>xercesImpl</artifactId>
    <version>2.11.0</version>
</dependency>

Вы можете найти зависимость для вашего любимого инструмента сборки здесь: http://mvnrepository.com/artifact/xerces/xercesImpl/2.11.0.

Вы могли бы, вероятно, все сделать с помощью XSLT-файла. Google выдает несколько результатов, но я не могу комментировать их правильность.

Чтобы сделать вывод действительным документом XML, НЕТ. Допустимый документ XML должен начинаться с инструкции по обработке. См. Спецификацию XML http://www.w3.org/TR/REC-xml/ для получения более подробной информации.

Другие вопросы по тегам