与xsltproc相比,xsl:apply-templates / xsl:with-param与Xalan-J和saxon的意外行为

时间:2012-02-09 11:36:04

标签: java xslt xslt-1.0 saxon xalan

我正在努力学习如何从java代码中使用XSLT 1.0,但随着时间的推移,我开始逐渐放松思绪。

我的类路径上有Xalan-J(包含xalan.jar和xsltc.jar以及所有依赖关系jar),saxon和jing(后两个在我的项目中使用els)并使用JAXP和System的组合。 setProperty调用以我想要的方式强制使用类实现,例如TransformerFactory。这使我能够通过简单地从代码中更改属性来查看不同的XSLT处理器使用单个XSL转换文件的行为。此外,我还使用来自cygwin环境的xsltproc来查看它的功能。我也在Oxygen中调试,以确保我的java代码不是问题。

看看这个虚拟的XSL:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"                
                xmlns:rng="http://relaxng.org/ns/structure/1.0"
                xmlns:ex="http://example.com/ns/ex"
                version="1.0">

  <xsl:output method="xml" encoding="utf-8"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="/">
    <!-- Start by finding the root grammar element -->
    <xsl:apply-templates select="rng:grammar"/>
  </xsl:template>

  <xsl:template match="/rng:grammar">
    <!-- Continue with child grammar elements -->
    <xsl:apply-templates select="descendant::rng:grammar"/>
  </xsl:template>

  <xsl:template match="rng:grammar">
    <!-- set the variable and pass it's value to another template -->
    <xsl:variable name="parameter" select="'any-string-value'"/>
    <xsl:message>initial value: <xsl:value-of select="$parameter"/></xsl:message>
    <xsl:apply-templates select="descendant::ex:data">
      <xsl:with-param name="parameter" select="$parameter"/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="rng:optional">
    <!-- use the param value here -->
    <xsl:param name="parameter"/>
    <xsl:message>final value: <xsl:value-of select="$parameter"/></xsl:message>
  </xsl:template>

</xsl:stylesheet>

除了调用一些可用于此虚拟XML实例文档的模板之​​外,它什么都不做:

<?xml version="1.0" encoding="UTF-8"?>
<grammar
   xmlns="http://relaxng.org/ns/structure/1.0"
   xmlns:ex="http://example.com/ns/ex"
   datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
  <start>
    <grammar ex:subgram="something" ns="http://example.com/ns/something">
      <start>
        <ex:data>
          <optional />
        </ex:data>
      </start>
    </grammar>
  </start>
</grammar>

我不知道我做错了什么,但传递唯一变量的值,因为XSL只能用于xsltc和xsltproc。正常的xalan和saxon都无法通过该值。见下面的结果。

xsltproc的:

$ xsltproc transformation.xsl instance.xml
initial value: any-string-value
final value: any-string-value

Xalan编译处理器(xsltc以及java 1.6默认实现):

Implementation: org.apache.xalan.xsltc.trax.TransformerFactoryImpl loaded from: ./lib/xalan-j_2_7_1/xsltc.jar
initial value: any-string-value
final value: any-string-value

Xalan Interpretive processor(xalan):

Implementation: org.apache.xalan.processor.TransformerFactoryImpl loaded from: ./lib/xalan-j_2_7_1/xalan.jar
initial value: any-string-value
final value:

撒克逊:

Implementation: com.icl.saxon.TransformerFactoryImpl loaded from: ./lib/saxon6-5-5/saxon.jar
initial value: any-string-value
final value:

我需要使用xalan(原因是可接受的EXSLT支持)。我不知道什么可能是不同产出的原因。我认为所有这些处理器都实现了XSLT 1.0,但我猜他们会采用不同的方式。我正在尝试在我的XSL中不符合XSLT 1.0吗?我可以用它来解决这个问题吗?

1 个答案:

答案 0 :(得分:2)

解释很简单:

  <xsl:template match="rng:optional">
    <!-- use the param value here -->
    <xsl:param name="parameter"/>
    <xsl:message>final value: <xsl:value-of select="$parameter"/></xsl:message>
  </xsl:template>

rng:optionalex:data的孩子。

没有模板匹配ex:data,因此它由元素节点的XSLT内置模板处理。

当然,内置模板对传递给它的参数一无所知,因此它不会将它们传递给它应用的下一个模板。

因此,选择模板匹配rng:optional(上面)以供XSLT元素的内置模板执行,并且不会将任何参数传递给此选定模板。

因此,parameter param的值是空字符串,您可以从Saxon和XalanJ获得正确的输出。