在Java中序列化Document对象,同时保留任意元素的格式

时间:2011-11-28 08:20:18

标签: java xml serialization

我正在使用下面的函数将DOM Document对象转换为Java中的String。

public static String convertDocumentToString(final Document doc) {
    final DOMImplementationLS domImplementation = (DOMImplementationLS) doc.getImplementation();
    final LSSerializer lsSerializer = domImplementation.createLSSerializer();
    lsSerializer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE);
    final String xml = lsSerializer.writeToString(doc);

    return xml;
}

这在大多数情况下效果很好,但是有一些我不想格式化的特定元素(例如屏幕DocBook元素)。所以我有两个问题:

  1. 在Java中格式化XML时是否有办法跳过某些元素,如上面的代码?
  2. 如果没有,是否有另一种方法将文档转换为字符串,同时保留任意元素的布局?
  3. 请注意,我过去也使用过Transformer(请参阅Getting xml string from Document in Java),但这并未保留CDATA部分。

    更新

    我很清楚,我正在反序列化和序列化XML,以便创建一个可以通过DOM以编程方式编辑的Document对象,序列化过程最好“漂亮地打印”生成的XML(除了一些任意的)元件)。

    更新2:

    最后,我创建了一个自定义函数,将Node转换为具有可选格式的String。请参阅https://sourceforge.net/p/commonclasses/code/110/tree/trunk/src/com/redhat/ecs/commonutils/XMLUtilities.java处的convertNodeToString函数,如下所示:

    final String exampleXml = FileUtilities.readFileContents(new File("test.xml"));
    
    final ArrayList<String> contentsInlineElements = new ArrayList<String>();
    contentsInlineElements.add("title");
    contentsInlineElements.add("term");
    
    final ArrayList<String> inlineElements = new ArrayList<String>();
    inlineElements.add("prompt");
    inlineElements.add("command");
    inlineElements.add("firstterm");
    inlineElements.add("ulink");
    inlineElements.add("guilabel");
    inlineElements.add("filename");
    inlineElements.add("replaceable");
    inlineElements.add("parameter");
    inlineElements.add("literal");
    inlineElements.add("classname");
    inlineElements.add("sgmltag");
    inlineElements.add("guibutton");
    inlineElements.add("guimenuitem");
    inlineElements.add("guimenu");
    inlineElements.add("menuchoice");
    inlineElements.add("citetitle");
    
    final ArrayList<String> verbatimElements = new ArrayList<String>();
    verbatimElements.add("screen");
    verbatimElements.add("programlisting");
    
    final Document doc = XMLUtilities.convertStringToDocument(exampleXml);
    final String formattedXml = XMLUtilities.convertNodeToString(doc.getDocumentElement(), true, false, false, verbatimElements, inlineElements, contentsInlineElements, true, 1, 0);
    

3 个答案:

答案 0 :(得分:0)

序列化旨在通过传输介质获取数据,但不一定(甚至通常)以与输入数据形式相符的方式获取数据,如果该形式根据定义不携带任何额外信息(原样) XML文档的情况)。

如果你需要继承设计,你必须将这个“元”信息(即格式)编码到数据本身,例如通过转移空白等。也许是最简单的解决方案,但是让你不要简单地“阅读”(就像你的眼睛一样)传输流,就是用像Base64这样的格式化数据进行编码。这将完美地在XML包装器内传输,同时保留您输入编码器的原始输入数据的保真度。

另一方面,当然,您必须再次对数据进行解码,然后才能继续进行处理。

答案 1 :(得分:0)

简短的回答:你做不到。当你告诉序列化程序要漂亮打印时,你要说明元素间空格的使用(即,它是可忽略的)。

答案越长:你不能不修改DOM(或它的副本)。 IMO最简单的方法如下:

  1. 标识要保留的节点。我假设你有一个ID或其他方法来使用XPath选择它。
  2. 调用Document.adoptNode()将该节点移动到新DOM中。我记得这个方法存在一些问题,但那是很多年前的事了。如果它不起作用,请使用Document.importNode()并从源文档中显式删除该节点。我相信您可以采用节点作为文档的根目录,但不能保证。
  3. 将文本节点插入包含唯一内容的原始文档。生成唯一内容的简便方法是UUID.randomUUID().toString()
  4. 将两个文档转换为字符串,漂亮打印一个,而不是另外打印另一个。
  5. 使用String.replace()将漂亮打印的文档插入漂亮的文档中。
  6. 而且,与往常一样,如果您计划将这些字符串写入文件或其他面向字节的格式,则必须显式编码为UTF-8。

答案 2 :(得分:-4)

在CDATA部分以外的XML文档中,空格并不重要,并且没有一个标准工具可以保留它。任何相反的要求都是不正确的。