【问题标题】:Does Xalan with Java 6 skip comments?带有 Java 6 的 Xalan 会跳过注释吗?
【发布时间】:2014-05-24 20:35:45
【问题描述】:

在我看来,JDK 6(和 7)附带的 Xalan 版本不处理输入文件中的 cmets,如 <xsl:template match="comment()" ...>... 指定的那样

给定以下输入文件,dangling.xml

<?xml version="1.0" ?>
<dangling xmlns:dt="urn:uuid:e2973380-8daf-11e3-a5d8-0002a5d5c51b">
   <!--  This is a comment. -->
   <foobar x="y">A bar where I drink foo beer,
           after debugging XSLT in hell all day.</foobar>
</dangling>

和样式表 identity_sans_dt.xsl

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:dt="urn:uuid:e2973380-8daf-11e3-a5d8-0002a5d5c51b">


<xsl:output method="xml"
            encoding="UTF-8"
            indent="yes" 
            omit-xml-declaration="yes"
            />

   <xsl:template match="/ | attribute::* | comment()">
     <xsl:copy>
       <xsl:apply-templates select="@*|node()"/>
     </xsl:copy>
   </xsl:template>
   <xsl:template match="*">
      <xsl:element name="{name()}">
         <xsl:apply-templates select="@*|node()"/>
      </xsl:element>
   </xsl:template>
</xsl:stylesheet>

我使用 libxml 的 xsltproc 得到以下输出

<dangling>
   <!--  This is a comment. -->
   <foobar x="y">A bar where I drink foo beer,
           after debugging XSLT in hell all day.</foobar>
</dangling>

但是,当我通过使用 SAX TransformerHandler 应用相同样式表的 Java 程序运行相同的事情时,我得到了这个。

<dangling>

   <foobar x="y">A bar where I drink foo beer,
           after debugging XSLT in hell all day.</foobar>
</dangling>

我是否做错了什么导致技术规范委婉地称为“不可预测的结果”?还是似乎有一个 Xalan 错误导致 Java 版本中注释的遗漏?

虽然与 comment() 处理的问题没有直接关系,但这里是本练习的背景。 dangling.xml 是一些先前处理的结果,这些处理已经剥离了 dt 命名空间中的所有元素及其子元素。出于某种原因,dt 命名空间声明被留下了。此外,xml 声明引起了一些问题。 (这是因为一些下游代码将其作为字符串进行操作,然后将其放入另一个 XML 文本字符串的中间。不要告诉我这有多可怕;我知道。不要告诉那些负责说代码;我已经这样做了。)所以我花了很多时间试图摆脱这两个烦人的工件,但保留其他所有东西。

不,dangling.xml 不是真正的文件,只是调试的代理。 :-)

因此,如果有一种完全更好的方法可以回避整个问题,我也有兴趣了解这一点。

提前谢谢你。

【问题讨论】:

    标签: java xml xslt xalan


    【解决方案1】:

    可能是你运行不正确。在 SAX 中,XMLReader 将大多数解析事件通知给已注册的 ContentHandler,但不通知 cmets,它们将发送给已注册的 LexicalHandler。 JAXP TransformerHandler 实现了 ContentHandler 和 LexicalHandler 接口,但只有在 XMLReader 中注册为 ContentHandler 和 LexicalHandler 时才会通知 cmets。

    【讨论】:

    • 谢谢迈克尔。 XMLReader 上没有 setLexicalHandler 方法;见docs.oracle.com/javase/6/docs/api/org/xml/sax/XMLReader.html。有问题的代码实际上使用了 TransformerHandler,它设置为 TransformerHandler 上的 ContentHandler。那么如何指定这也是 LexicalHandler 呢?
    • 更新:根据 Michael 的建议,我在 JavaDocs 中搜索了 setLexicalHandler。 SAXResult 上有这样一个方法,但它声明“如果未设置词法处理程序,则转换器应尝试将 ContentHandler 转换为 LexicalHandler。”所以 TransformerHandler 已经在做这两件事了。但是,StreamResult(在 TransformerHandler 上为其输出设置)没有这样的选项。这是否意味着无法使用 SAX 流出评论节点?在我看来这不太可能。
    【解决方案2】:

    我会为遇到这个烦人问题的其他人提供答案。

    但首先,我要再次感谢 Michael Kay 为我指明最终解决方案的方向。

    问题在于需要在最初处理输入的原始 XMLReader 上设置词法处理程序。我错误地将问题解释为必须有一个词法处理程序来获取 cmets 以编写最终结果。所以我误解了给出的建议。

    在进行更多研究后,我找到了后续问题的答案,即“如何在 XMLReader 上设置词法分析器?”在我看来,这是非常隐蔽的。与 SAXResult 上的直接 setLexicalHandler 方法不同,SAXParser 和 XMLReader 对象上都有一个 setProperty 方法。

     void XMLReader.setProperty(String name, Object value);
     void SAXParser.setProperty(String name, Object value);
    

    “标准”属性名称是在 http://sax.sourceforge.net/apidoc/org/xml/sax/package-summary.html#package_description 指定的 URL。其他实现可能会添加自己的特殊属性,只要它们使用不与标准冲突的 URL。这似乎是一种很好的扩展机制,但我不明白他们为什么将它用于作为 API 标准部分的对象;或者,相反,为什么他们没有以相同的方式指定所有内容(包括 ContentHander)。 (换句话说,要始终如一地这样做。)

    因此,代替什么,在我的拙见中应该是一个简单的 setLexicalHandler 方法,必须使用字符串 ""http://xml.org/sax/properties/lexical-handler" 来指示正在设置词法处理程序,并提供处理程序作为第二个(非类型安全对象)参数。

    所以这是我的程序“前端”的相关部分:

            saxReader = saxParserFactory.newSAXParser().getXMLReader();
            saxReader.setContentHandler(transformsHandler);
            saxReader.setProperty("http://xml.org/sax/properties/lexical-handler", transforms[0]);
    

    如果您未能包含 setProperty 调用,您的转换器将永远不会看到输入中的 cmets,因此,在我的情况下,您的 XSLT 是否处理它们都无关紧要。这就是迈克尔最初的简明解释。

    【讨论】:

    • 感谢您添加血淋淋的细节,我记得几年前我最后一次在这个领域做任何事情时都在苦苦挣扎。
    【解决方案3】:

    最后我检查了一下,Sun/Oracle JRE 附带的 Apache Xalan 和 Xerces 版本已经过时多年,并且有许多已知的错误和限制。除非 Oracle 在 Java 7 或 Java 8 中纠正了这个问题——即使他们已经纠正了——我强烈建议您直接从 Apache 下载当前副本并改用它们。

    (IBM JRE——可惜,它只能作为 IBM 产品的一部分才可用——更密切地跟踪 Apache,部分原因是 IBM 团队是 Xalan 和 Xerces 的最初捐助者,并一直参与支持它们。最近的 IBM JRE 用 IBM 的下一代 XSLT 处理器 XL-TXE 取代了 Xalan。IBM WebSphere 发布了 XL-TXE 的高级版本作为其 XML Feature Pack 的一部分;该版本增加了对 XQuery 1.0、XSLT 2.0 和 XPath 2.0 的支持。 )

    【讨论】:

    • 还有 Saxon,它至少实现了 XSLT 2.0。 Apache Xalan 本身一直停留在 1.0,自 2007 年以来甚至没有重新发布。
    • 是的。 IBM 团队为 Xalan 做出了如此多贡献的问题在于,当他们不得不将注意力从 Xalan 上转移开时,并没有很多其他人准备好弥补这一缺陷。
    猜你喜欢
    • 2014-07-28
    • 1970-01-01
    • 2011-12-30
    • 1970-01-01
    • 2012-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-19
    相关资源
    最近更新 更多