【问题标题】:Adding linebreak in xml file before root node在根节点之前的xml文件中添加换行符
【发布时间】:2014-08-24 11:23:34
【问题描述】:

我正在尝试在 XML 文档中根节点上方的 cmets 之后添加换行符。

我需要这样的东西:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--DO NOT EDIT THIS FILE-->
<projects>
</projects>

但我能得到的是这个(根内的换行符,但我需要在评论后换行):

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--DO NOT EDIT THIS FILE--><projects>

</projects>

我需要在我的评论之后添加换行符。有没有办法做到这一点?

我的代码:

import java.io.File;
import java.io.FileInputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

public class XMLNewLine {
    /**
     * @param args
     */
    public static void main(String[] args) {
        System.out.println("Adding comment..");

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

        dbf.setValidating(false);
        DocumentBuilder db;

        try {
            Document doc;
            StreamResult result;
            result = new StreamResult(new File("abc.xml"));
            db = dbf.newDocumentBuilder();
            doc = db.parse(new FileInputStream(new File("abc.xml")));

            Element element = doc.getDocumentElement();
            Text lineBreak = doc.createTextNode("\n");

            element.appendChild(lineBreak);
            Comment comment = doc
                    .createComment("DO NOT EDIT THIS FILE");
            element.getParentNode().insertBefore(comment, element);
            doc.getDocumentElement().normalize();
            TransformerFactory transformerFactory = TransformerFactory
                    .newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            DOMSource source = new DOMSource(doc);
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.transform(source, result);

        } catch (Exception e) {
            // TODO Auto-generated catch block

        }

    }
}

【问题讨论】:

  • “我正在尝试在 XML 文档中根节点上方的 cmets 之后添加换行符。” - 你到底为什么要这样做?
  • (不要回答,这是一个反问。我理解这纯粹是为了美观。我也不是说不可能。)
  • @tomalak 感谢您的回复。这是为了确保文件在发货前看起来良好且可读。

标签: java xml line-breaks domparser


【解决方案1】:

你基本上想要一个文本节点,在评论节点之后包含一个换行符。

Element docElem = doc.getDocumentElement();

doc.insertBefore(doc.createComment("DO NOT EDIT THIS FILE"), docElem);
doc.insertBefore(doc.createTextNode("\\n"), docElem);


编辑:似乎在org.w3c.dom.Document 的根节点上甚至不允许附加仅包含空格的文本节点。这在形式上是 100% 正确的,但也无济于事。

Transformer 的输出中呈现cmets 的方式取决于它使用的序列化程序(HTML、XML 和纯文本输出有不同的序列化程序)。在内置的 XML 序列化程序中,注释的结尾被定义为 --&gt; - 没有换行符。

由于javax.xml.transform.Transformer 的内部是硬连线的,序列化程序不是公共API,并且类被标记为final,覆盖该行为或设置自定义序列化程序是不可能的。

换句话说,您很不幸以干净的方式添加换行符。

但是,您可以安全地以稍微不干净的方式添加它:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();

FileInputStream inputXml = new FileInputStream(new File("input.xml"));
Document doc = db.parse(inputXml);

// add the comment node    
doc.insertBefore(doc.createComment("THIS IS A COMMENT"), doc.getDocumentElement());

StringWriter outputXmlStringWriter = new StringWriter();
Transformer transformer = transformerFactory.newTransformer();
// "xml" + "UTF-8" "include XML declaration" is the default anyway, but let's be explicit
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.transform(new DOMSource(doc), new StreamResult(outputXmlStringWriter));

// now insert our newline into the string & write an UTF-8 file
String outputXmlString = outputXmlStringWriter.toString()
    .replaceFirst("<!--", "\n<!--").replaceFirst("-->", "-->\n");

FileOutputStream outputXml = new FileOutputStream(new File("output.xml"));            
outputXml.write(outputXmlString.getBytes("UTF-8"));

通常强烈建议不要对 XML 字符串执行搜索和替换操作,但在这种情况下几乎不会出错。

【讨论】:

  • 我遇到了错误 _org.w3c.dom.DOMException: HIERARCHY_REQUEST_ERR: 试图插入一个不允许的节点。 _ 什么时候使用下面的代码:doc.insertBefore(doc.createTextNode("\\n"), docElem);
  • @Murali 查看修改后的答案。
【解决方案2】:

一段时间后重新访问,因为我遇到了同样的问题。我找到了另一个不需要在字符串中缓冲输出的解决方案:

  1. 通过传递一个空文档只编写 XML 声明。这也会附加一个换行符。

  2. 不使用 XML 声明编写文档内容

代码:

StreamResult streamResult = new StreamResult(writer);
// output XML declaration with an empty document
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.transform(new DOMSource(), streamResult);
// output the document without XML declaration
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(new DOMSource(doc), streamResult);

【讨论】:

    【解决方案3】:

    您可以通过不将注释节点添加到文档中来实现此目的,而是对文档进行部分转换。先把自己的XML处理指令和注释分别转换,再转换文档的其余部分:

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document doc = db.parse(new FileInputStream(new File("abc.xml")));
    
    Result output = new StreamResult(new File("abc.xml"));
    Source input = new DOMSource(doc);
    
    
    // xml processing instruction and comment node
    ProcessingInstruction xmlpi = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"");
    Comment comment = doc.createComment("DO NOT EDIT THIS FILE");
    
    // first transform the processing instruction and comment
    transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
    transformer.transform(new DOMSource(xmlpi), output);
    transformer.transform(new DOMSource(comment), output);
    // then the document
    transformer.transform(input, output);
    

    【讨论】:

    • 它适用于FileOutputStream 而不是File in Result output = new StreamResult(new FileOutputStream("abc.xml"));
    【解决方案4】:

    有一个JDK bug 与此有关。它没有得到修复(如您所料),因为这可能会给用户现有的应用程序带来很多问题。

    添加以下输出属性可以解决此问题:

    transformer.setOutputProperty("http://www.oracle.com/xml/is-standalone", "yes");
    

    【讨论】:

      【解决方案5】:

      有同样的问题。 我通过将注释放在根元素中来解决它。 不完全一样,但我认为可以接受。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-01
        • 1970-01-01
        相关资源
        最近更新 更多