Java 1.6:javax.xml.transform.Transformer拒绝缩进包含换行符的xml字符串

时间:2011-08-04 12:58:31

标签: java xml jdk1.6 indentation transformer

我需要能够使用Java API轻松打印xml字符串,并且已经在Web和此特定网站上找到了多种解决方案。然而,尽管多次尝试将其与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。

这个问题与(可能与众多其他人)有关但与以下内容不同:

How to pretty print XML from Java?

indent XML text with Transformer

Indent XML made with Transformer

1 个答案:

答案 0 :(得分:1)

我得出结论,这是Transformer的正常行为。更。它的缩进功能并不意味着可以用作漂亮的打印机,而不是单独使用它。当XML被打印出来时,它的结构会发生变化,除非你确切地知道文档应该是什么样子(基于它的XSD,DTD或类似的东西)。这是确定哪些换行符被视为可忽略空格以及哪些是实际元素值或它们的一部分的唯一方法。 Transformer不会重新格式化现有的空格,这就是我的代码输出就是这样的原因。

因此,如果您想使用Transformer或任何其他类打印已经很漂亮的XML字符串,首先必须摆脱可忽略的空白,安全地做到这一点的唯一方法是知道XML文档的结构是什么应该是这样的。我希望有人为我确认这个声明,因为这只是我的假设。如果这个陈述是正确的;第三方漂亮的打印机怎么做呢?我知道JTidy并不需要XSD,但无论如何都要打印出来。它是否只是将所有空格视为可忽略的空格,除非它被包含在文本XML节点中?还有其他方法可以确定和消除可忽略的空格吗?