以漂亮的方式。忽略空格

时间:2010-09-07 14:15:20

标签: java xml dom removing-whitespace

温柔的。

我正在尝试使用javax.xml.transform.Transformer将某些xml字符串格式化为标记之间的缩进/空格。如果标签之间没有空格,则可以正常工作。如果它有行为怪异。我会发一个例子。我尝试跟进以下主题:http://forums.sun.com/thread.jspa?messageID=2054303#2699961。没有成功。

要遵循的代码:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
   factory.setIgnoringElementContentWhitespace(true);
   DocumentBuilder builder = factory.newDocumentBuilder();
   DOMImplementation domImpl = builder.getDOMImplementation();
   DOMImplementationLS ls = (DOMImplementationLS) domImpl.getFeature("LS", "3.0");
   LSInput in = ls.createLSInput();
   in.setByteStream(new ByteArrayInputStream(input.getBytes()));
   LSParser parser = ls.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS,
     "http://www.w3.org/2001/XMLSchema");
   Document xmlInput = parser.parse(in);

   StringWriter stringWriter = new StringWriter();
   StreamResult xmlOutput = new StreamResult(stringWriter);
   TransformerFactory f = TransformerFactory.newInstance();
   f.setAttribute("indent-number", 2);

   Transformer transformer = f.newTransformer();
   transformer.setOutputProperty(OutputKeys.INDENT, "yes");
   transformer.setOutputProperty(OutputKeys.METHOD, "xml");
   transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
   transformer.transform(new DOMSource(xmlInput), xmlOutput);

如果标签之间没有中断

input : <tag><nested>    hello   </nested></tag>
output : 
<tag>
  <nested>    hello   </nested>
</tag>

如果有:

input : <tag>  <nested>    hello   </nested></tag>
output : 
<tag>  <nested>    hello   </nested>
</tag>

JVM 1.6。

这里有明显的错误吗?

2 个答案:

答案 0 :(得分:3)

这必须是变压器实施的问题。我创建了一个小型测试类,它读取没有空格或换行符的字符串作为XML,并从XSLT样式表(也来自字符串)创建转换器。样式表指定必须进行缩进。这基本上是通过transformer.setOutputProperty(OutputKeys.INDENT, "yes");

实现目标的另一种方式

这是:

package transformation;

import java.io.StringReader;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

public class TransformerTest {

    public static void main(String[] args) throws Exception {

        final String xmlSample = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><tag><nested>hello</nested></tag>";
        final String stylesheet = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"><xsl:output method=\"xml\" version=\"1.0\" indent=\"yes\"/><xsl:template match=\"node()|@*\"><xsl:copy><xsl:apply-templates select=\"node()|@*\"/></xsl:copy></xsl:template></xsl:stylesheet>";

        final TransformerFactory factory = TransformerFactory.newInstance();

        final Source xslSource = new StreamSource(new StringReader(stylesheet));
        final Transformer transformer = factory.newTransformer(xslSource);

        final Source source = new StreamSource(new StringReader(xmlSample));
        final Result result = new StreamResult(System.out);

        transformer.transform(source, result);

    }

}

现在奇怪的是,根据我使用的变压器,结果会有所不同。如果我没有在类路径上放置任何TransformerFactory实现(使用JRE库中的默认实现),结果如下:

<?xml version="1.0" encoding="UTF-8"?>
<tag>
<nested>hello</nested>
</tag>

不正确,因为标签没有缩进。

然后,通过在类路径上添加最近的Xalan实现(xalan.jar和serializer.jar,仍然使用JRE默认解析器/ DOM构建器),我得到了这个:

<?xml version="1.0" encoding="UTF-8"?><tag>
<nested>hello</nested>
</tag>

仍然不正确,第一个标记与XML声明位于同一行,并且没有缩进。

老实说,这让我很震惊。我知道标签之间或文本节点周围的空格是否会影响缩进,因为变换器可能会认为其中一些是不可忽略的。但是看到一个简单的XML就像那个被破坏的那样简直就是奇怪了。我想也许使用控制台输出可能与它有关,所以我尝试流式传输到文件。结果相同。

奇怪的是,长期以来的变压器实现仍然存在这样的行为。但是,当我注意到使用Schema的Validator导致属性从“增强的”XML输出中删除时,并没有那么糟糕。

除了试图寻找其他处理器并看看它们是否遇到同样的问题之外,似乎没有太多可以做的事情。也许萨克森值得一试。这个错误报告也很有趣(但它适用于Java 1.5): http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6296446

答案 1 :(得分:0)

变压器似乎不喜欢白色空间,所以最简单的解决方案似乎就是简单 删除它....

    public String prettyPrintXML(String inXML)  {

       String outXML = inXML;

// The transformer doesn't like white space between tags so remove it.          
           String[] bits = inXML.split(">");      
       inXML="";
       boolean first = true;
       for (int n=0;n<bits.length; n++){
           if (first)
            inXML = inXML + bits[n].trim();
           else
             inXML = inXML + ">"+bits[n].trim();

           first = false;
       }
      inXML = inXML + ">";

将inXML传递到您的变压器中然后离开。