【问题标题】:Serialize a Document object in Java, while preserving the formatting of arbitrary elements在 Java 中序列化 Document 对象,同时保留任意元素的格式
【发布时间】:2011-11-28 08:20:18
【问题描述】:

我正在使用下面的函数将 DOM 文档对象转换为 Java 中的字符串。

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. 如果没有,是否有另一种方法可以将文档转换为字符串,同时保留任意元素的布局?

请注意,我过去也使用过 Transformer(请参阅 Getting xml string from Document in Java),但这并没有保留 CDATA 部分。

更新:

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

更新 2:

最后,我创建了一个自定义函数来将节点转换为具有可选格式的字符串。请参阅 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);

【问题讨论】:

    标签: java xml serialization


    【解决方案1】:

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

    如果您也需要延续设计,则必须将这些“元”信息(即格式)编码到数据本身中,例如通过转义空格等。这可能是最简单的解决方案,但可以防止您简单地“阅读”(如用您的眼睛)传输流,是将您的格式化数据编码为 Base64 之类的东西。这将在 XML 包装器内完美传输,同时保持您输入编码器的原始输入数据的保真度。

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

    【讨论】:

    • 我使用的工作流程是: 1. 反序列化 XML 字符串以创建 Document 对象 2. 处理 Document 对象(添加和删除元素) 3. 将 Document 对象序列化回 String,最好使用漂亮的印刷品。在这种情况下,“序列化”只是一种创建内存表示的方法,我可以通过 DOM 可靠地编辑 XML,而不是通过传输介质移动数据。
    • 嗯...我不知道有任何 XML 库(尽管我没有仔细研究过)可以从格式化中排除任意元素。我什至不确定这是否可以实施并满足所有需求。我认为您可能需要考虑 XML 中的 Base64(或任何其他)编码。至少会是一个可靠的实现,而不必担心 XML 依赖项的更新可能会在将来破坏一些东西。
    【解决方案2】:

    简短的回答:你不能。当您告诉序列化程序进行漂亮打印时,您就是在声明使用元素间空白(即,它是可忽略的)。

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

    1. 确定要保留的节点。我假设您有一个 ID 或其他方式来使用 XPath 选择它。
    2. 调用Document.adoptNode() 将该节点移动到新的DOM 中。我记得这种方法有一些问题,但那是很多年前的事了。如果它不起作用,请使用Document.importNode() 并从源文档中显式删除该节点。我相信您可以采用节点作为文档的根,但不能保证。
    3. 在原始文档中插入一个包含唯一内容的文本节点。生成独特内容的简单方法是UUID.randomUUID().toString()
    4. 将两个文档都转换为字符串,一个打印漂亮,另一个打印不漂亮。
    5. 使用String.replace() 将打印不漂亮的文档插入打印精美的文档中。

    而且,与往常一样,如果您打算将这些字符串写入文件或其他面向字节的格式,您必须明确编码为 UTF-8。

    【讨论】:

      【解决方案3】:

      除了 CDATA 部分之外,空白在 XML 文档中并不重要,并且没有任何标准工具旨在保留它。任何相反的要求都是不正确的。

      【讨论】:

      • @downvoter 请解释一下。如果这里有错误,社区应该知道它是什么,就像我一样。
      • 我没有投反对票,但空格在 XML 文档中非常重要。唯一不重要(“可忽略的空格”)是当您有一个 DTD 时,该 DTD 专门将构造定义为“元素内容”。见xml.com/axml/target.html#sec-element-contentxml.com/axml/target.html#sec-white-space(尤其是第一个注释)
      • 好的,现在我投了反对票。答案不正确且具有误导性,您有机会编辑/删除。
      • 在这种情况下,空格会产生重大影响,尽管它不在 CDATA 部分中。请参阅docbook.org/tdg5/en/html/screen.html:“此元素“逐字”显示;该元素中的空格和换行符很重要。”
      猜你喜欢
      • 2017-01-07
      • 1970-01-01
      • 2020-10-23
      • 1970-01-01
      • 1970-01-01
      • 2012-04-28
      • 2016-06-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多