JDOM Transformer - 不要收缩空元素

JDOM Transformer - don't contract empty elements

我正在使用 JDOM 2.0.6 将 XSLT 转换为 HTML,但我遇到了以下问题 - 有时数据应该是空的,也就是说,我将在我的 XSLT 如下:

<div class="someclass"><xsl:value-of select="somevalue"/></div>

somevalue为空时,我得到的输出是:

<div class="someclass"/>

可能完全有效 XML,但 无效 HTML,并且在显示结果页面时会导致问题。 <span><script> 标签会出现类似的问题。

所以我的问题是 - 我如何告诉 JDOM 不要收缩空元素,并将它们保留为 <div></div>

编辑
我怀疑问题不在实际的 XSLTTransformer 中,而是后来使用 JDOM 写入 html 时的问题。这是我使用的代码:

XMLOutputter htmlout = new XMLOutputter(Format.getPrettyFormat());
htmlout.getFormat().setEncoding("UTF-8");

Document htmlDoc = transformer.transform(model);
htmlDoc.setDocType(new DocType("html"));

try (OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(outHtml), "UTF-8")) {
    htmlout.output(htmlDoc, osw);
}

目前建议的添加零宽度 space 的解决方案对我有用,但我想知道是否有办法告诉 JDOM 将文档视为 HTML (无论是在转换阶段还是输出阶段,但我猜问题出在输出阶段)。

在您的例子中,XML 转换直接发生在 file/stream 上,它不再受 JDOM 控制。

在 JDOM 中,您可以selectJDOM 文档的输出是扩展的,还是空元素的未扩展输出。通常,人们从 JDOM 得到如下输出:

XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat());
xout.output(document, System.out);

不过,您可以修改输出格式,expand the empty elements

Format expanded = Format.getPrettyFormat().setExpandEmptyElements(true);
XMLOutputter xout = new XMLOutputter(expanded);
xout.output(document, System.out);

如果您 'recover'(假设它是有效的 XHTML?)XSLT 转换 xml 作为新的 JDOM 文档,您可以输出带有扩展空元素的结果。

您可以在元素之间使用 zero-width-space。这不会影响 HTML 输出,但会保持打开-关闭标签分开,因为它们具有非空内容。

<div class="someclass">&#8203;<xsl:value-of select="somevalue"/></div>

缺点是:标签不再是空的。如果您的输出是 XML,那将很重要。但是对于 HTML - 这可能是处理的最后阶段 - 应该无关紧要。

如果要转换为 HTML 文件,请考虑将 Jaxp TransformerJDOMSourceStreamResult 一起使用,然后转换器将序列化转换结果为 HTML 如果输出方法是 html(在您的代码中设置或使用名为 html.

的无命名空间根元素完成

除了 "expandEmptyElements" 选项之外,您还可以创建自己的编写器并将其传递给 XMLOutputter:

XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat().setExpandEmptyElements(true));
StringWriter writer = new HTML5Writer();
outputter.output(document, writer);
System.out.println(writer.toString());

此作者随后可以修改所有 HTML5 个无效元素。例如 "script" 这样的元素不会被触及:

private static class HTML5Writer extends StringWriter {

    private static String[] VOIDELEMENTS = new String[] { "area", "base", "br", "col", "command", "embed", "hr",
            "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr" };

    private boolean inVoidTag;
    private StringBuffer voidTagBuffer;

    public void write(String str) {
        if (voidTagBuffer != null) {
            if (str.equals("></")) {
                voidTagBuffer.append(" />");
                super.write(voidTagBuffer.toString());
                voidTagBuffer = null;
            } else {
                voidTagBuffer.append(str);
            }
        } else if (inVoidTag) {
            if (str.equals(">")) {
                inVoidTag = false;
            }
        } else {
            for (int i = 0; i < VOIDELEMENTS.length; i++) {
                if (str.equals(VOIDELEMENTS[i])) {
                    inVoidTag = true;
                    voidTagBuffer = new StringBuffer(str);
                    return;
                }
            }
            super.write(str);
        }
    }

}

我知道,这很脏,但我遇到了同样的问题,但没有找到任何其他方法。