Java XMLSerializer避免复杂的空元素。

3

我有这段代码:

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    DOMImplementation impl = builder.getDOMImplementation();
    Document xmldoc = impl.createDocument(null, null, null);

    Element root = xmldoc.createElement("root");
    Element textElement = xmldoc.createElement("text");
    Text textNode = xmldoc.createTextNode("");
    root.appendChild(textElement);
    textElement.appendChild(textNode);

    OutputFormat of = new OutputFormat("XML","UTF-8",true);
    of.setIndent(1);
    of.setIndenting(true);

    ByteArrayOutputStream stream = new ByteArrayOutputStream();

    XMLSerializer serializer = new XMLSerializer(stream, of);
    // As a DOM Serializer
    serializer.asDOMSerializer();
    serializer.serialize(root);

    System.out.println(stream.toString());

我需要打印出以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <text/>
</root>

但是,我想要得到这个:
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <text></text>
</root>

有没有人知道如何设置XMLSerializer以避免复杂的空元素呢? 谢谢。


我认为你不能改变那个。两个版本是相等的。你为什么要避免复杂的空元素? - Mircea
我的应用程序是一种在两个应用程序之间进行转换的工具,它将应用程序1生成的文件解析为一个XML文件,并将其作为应用程序2的输入。但是应用程序2不接受这种类型的输入。难道没有通过doctype或类似方式设置的可能性吗? - xMichal
从语言定义的角度来看,这两个版本是等效的,因此在DTD或XSD中没有构造可以防止使用空标签。我的意见是您应该使app2接受输入(因为它是有效的输入,所以应该被处理),或者如果无法访问该应用程序,则可以更改由app1返回的xml字符串(stream.toString())。 更确切地说,您应该在字符串中查找所有“<tag/>”模式,并将其替换为“<tag></tag>”。我认为,为了软件的稳定性,您应该使app2接受具有空元素的输入。 - Mircea
1
一个不接受<tag/>的应用不能声称能读取 XML。 - Jim Garrison
2个回答

3
结果:我认为这是不可能的。XMLSerializer不支持此配置。 分析:当您调用serializer.serialize(root)时,将调用BaseMarkupSerializer的serialize(Element)方法。它定义了您传递给序列化的节点类型,并选择适当的处理方式。
当涉及文本节点时,它调用XMLSerializer的serializeElement(Element)方法:
// If element has children, then serialize them, otherwise
// serialize en empty tag.       
if (elem.hasChildNodes()) {
    //... irrelevant code...
    endElementIO( null, null, tagName );
} else {
    //... irrelevant code...
    _printer.printText( "/>" ); // <------ HARDCODED, NON-CONFIGURABLE
    //... irrelevant code...
}

问题: 你可以看到,关闭空元素的方式是硬编码的,而且不可配置(如果你从源代码中查找完整的代码片段的话)。

解决方案: 由于XMLSerializer并不是最终版本,所以你可以通过扩展它并重写它的方法来创建自己的序列化程序。其中一种方式是改变:

_printer.printText( "/>" );

to

_printer.printText( "</" );
_printer.printText( elem.getTagName() );
_printer.printText( ">" );

观点:我不确定是否没有干净的解决方案,我认为这个解决方案是最后的选择。无论如何,您应该通过源代码和/或文档查找更多信息。


+1 标准的Xerces序列化程序绝对不可能做到这一点。其他序列化程序可能可以实现,但我目前不知道任何可以实现此功能的程序,并且在谷歌上也找不到任何相关信息。 - Jim Garrison

1

我曾经遇到过XMLSerializer不允许对空标签进行渲染自定义的问题。我的解决方案是扩展原始的XMLSerializer代码并覆盖serializeElement方法:

我复制了原始代码并更改了关闭打印部分:

protected void serializeElement(Element elem) throws IOException ...

if (isSelfClosingElement(elem))
    _printer.printText("/>");
else
_printer.printText("></" + elem.getTagName() + ">");

其中 isSelfClosingElement 保存了自闭合元素的列表

注意:此外,您需要复制 printAttribute()printNamespaceAttr() 方法,因为它们被标记为私有而不是受保护。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接