Java 1.6: javax.xml.transform.Transformer отказывается делать отступ для строк XML, которые содержат переводы строк - PullRequest
2 голосов
/ 04 августа 2011

Мне нужно уметь красиво печатать XML-строки с помощью API Java, и я нашел несколько решений для этого как в Интернете, так и на этом конкретном веб-сайте. Однако, несмотря на многочисленные попытки заставить это работать с javax.xml.transform.Transformer, это было пока неудачей. Приведенный ниже код работает только частично, когда строка xml в аргументе не содержит никаких новых строк между элементами xml. Это просто не будет делать. Мне нужно уметь печатать что угодно, при условии, что он правильно сформирован и корректен в формате xml, даже если раньше были красивые печатные строки.

Я получил это (собрал из фрагментов кода, которые я нашел, люди утверждали, что это работает для них):

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

public class XMLFormatter {

    public static String format(String xml, int indent, boolean omitXmlDeclaration)
            throws TransformerException {

        if (indent < 0) {
            throw new IllegalArgumentException();
        }
        String ret = null;
        StringReader reader = new StringReader(xml);
        StringWriter writer = new StringWriter();
        try {
            TransformerFactory factory = TransformerFactory.newInstance();
            factory.setAttribute("indent-number", new Integer(indent));
            Transformer transformer = factory.newTransformer();
            if (omitXmlDeclaration) {
                transformer.setOutputProperty(
                        OutputKeys.OMIT_XML_DECLARATION, "yes");
            }
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty(
                    "{http://xml.apache.org/xslt}indent-amount",
                    String.valueOf(indent));
            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
            transformer.transform(
                    new StreamSource(reader),
                    new StreamResult(writer));
            ret = writer.toString();
        } catch (TransformerException ex) {
            throw ex;
        } finally {
            if (reader != null) {
                reader.close();
            }
            try {
                if (writer != null) {
                    writer.close();
                }
            } catch (IOException ex) {}
        }

        return ret;
    }

    public static void main(String[] args) throws TransformerException {
        StringBuilder sb = new StringBuilder();
        sb.append("<rpc-reply><data><smth/></data></rpc-reply>");

        System.out.println(sb.toString());
        System.out.println();
        System.out.println(XMLFormatter.format(sb.toString(), 4, false));

        final String NEWLINE = System.getProperty("line.separator");
        sb.setLength(0);
        sb.append("<rpc-reply>");sb.append(NEWLINE);
        sb.append("<data>");sb.append(NEWLINE);
        sb.append("<smth/>");sb.append(NEWLINE);
        sb.append("</data>");sb.append(NEWLINE);
        sb.append("</rpc-reply>");

        System.out.println(sb.toString());
        System.out.println();
        System.out.println(XMLFormatter.format(sb.toString(), 4, false));
    }
}

Этот код не должен беспокоить эти новые строки, не так ли? Это ошибка или я что-то упустил здесь? Вывод для фрагмента кода:

<rpc-reply><data><smth/></data></rpc-reply>

<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply>
    <data>
        <smth/>
    </data>
</rpc-reply>

<rpc-reply>
<data>
<smth/>
</data>
</rpc-reply>

<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply>
<data>
<smth/>
</data>
</rpc-reply>

Насколько я могу судить, мой код отличается от других примеров только тем, что я использую StringWriter и StringReader для метода transform (in, out). Я уже пытался преобразовать xml в ByteArrayOutputStream и даже проанализировать его с помощью DOM, а затем передать его в трансформатор, но результат тот же. Я был бы очень признателен, если бы знал, почему это работает только для однострочных строк.

Я использую jdk1.6_u24 в сочетании с Netbeans 6.9.1.

Этот вопрос относится (и, вероятно, ко множеству других), но не совпадает с:

Как красиво печатать XML с Java?

отступ XML-текста с помощью Transformer

Отступ XML, созданный с помощью Transformer

1 Ответ

1 голос
/ 17 августа 2011

Я пришел к выводу, что это нормальное поведение для Трансформера.Даже больше.Его функциональность отступа не предназначена для использования в качестве красивого принтера, в любом случае, сам по себе.Когда XML довольно печатный, его структура меняется, если вы точно не знаете, как должен выглядеть документ (на основе его XSD, DTD или чего-то подобного).Это единственный способ определить, какие символы новой строки следует считать игнорируемыми пробелами, а какие являются фактическими значениями элементов или их частью.Transformer не переформатирует существующий пробел, и поэтому вывод моего кода такой, какой он есть.

Так что, если вы хотите распечатать уже симпатичную напечатанную XML-строку, используя Transformer или любой другой класс, вы должны сначала получитьизбавьтесь от игнорируемых пробелов и единственный способ безопасно сделать это - узнать, какой должна быть структура вашего XML-документа.Я хотел бы, чтобы кто-то подтвердил это утверждение для меня, поскольку в настоящее время это только мое предположение.Если это утверждение верно;как это делают сторонние симпатичные принтеры?Я знаю, что JTidy не требовал XSD, но все равно довольно печатный.Он просто обрабатывает все пробелы как игнорируемые пробелы, если он не заключен в текстовый узел XML?Существуют ли другие методы определения и устранения игнорируемых пробелов?

...