与 xsltproc 相比,使用 Xalan-J 和 saxon 时 xsl:apply-templates/xsl:with-param 的意外行为
我正在尽力学习如何从 Java 代码中使用 XSLT 1.0,但随着时间的推移,我开始慢慢地失去理智。
我的类路径上有 Xalan-J(xalan.jar 和 xsltc.jar 以及所有依赖项 jar)、saxon 和 jing(后两者在我的项目中的其他地方使用),并且正在使用 JAXP 与 System.setProperty 调用的组合按照我想要的方式强制使用类实现,例如 TransformerFactory。这还使我能够通过简单地更改代码属性来了解使用单个 XSL 转换文件的不同 XSLT 处理器的行为。此外,我还在 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 解释处理器(xalan):
Implementation: org.apache.xalan.processor.TransformerFactoryImpl loaded from: ./lib/xalan-j_2_7_1/xalan.jar
initial value: any-string-value
final value:
saxon:
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?我可以使用一种解决方法来使其正常工作吗?
I'm trying my best to learn how to use XSLT 1.0 from java code but am starting to loose my mind bit by bit slowly over time.
I have Xalan-J (both xalan.jar and xsltc.jar with all dependency jars), saxon and jing (the latter two are used elswhere in my project) on my classpath and am using JAXP with a combination of System.setProperty calls to force usage of class implementations such as TransformerFactory the way I want. This also enables me to see how different XSLT processors behave using a single XSL transformation file by simply changing the properties from code. In addition I also use xsltproc from a cygwin environment to see what it does too. I also debug in Oxygen to make sure my java code is not the problem.
Take a look at this dummy 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>
It does nothing except calling some templates that work on this dummy XML instance document:
<?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>
I don't know what I'm doing wrong but passing the value of the only variable in that XSL works only with xsltc and xsltproc. Both normal xalan and saxon fail to pass the value. See results below.
xsltproc:
$ xsltproc transformation.xsl instance.xml
initial value: any-string-value
final value: any-string-value
Xalan Compiled processor (xsltc and also with java 1.6 default implementation):
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:
saxon:
Implementation: com.icl.saxon.TransformerFactoryImpl loaded from: ./lib/saxon6-5-5/saxon.jar
initial value: any-string-value
final value:
I need this to work with xalan (reason being acceptable EXSLT support). I have no idea what could possibly be the reason for different outputs. I tought all of these processors implement XSLT 1.0 but I guess they do it differently. Is what I'm trying to do in my XSL not XSLT 1.0 compliant? Is there a workaround I could use to get this to work?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
解释很简单:
rng:optional
是ex:data
的子级。ex:data
中没有模板匹配,因此它由元素节点的 XSLT 内置模板进行处理。当然,内置模板对传递给它的参数一无所知,因此它不会将它们传递到它应用的下一个模板。
因此,元素的 XSLT 内置模板会选择与
rng:Optional
(上文)匹配的模板来执行,并且不会向该选定模板传递任何参数。因此,
parameter
参数的值为空字符串,您可以从 Saxon 和 XalanJ 获得正确的输出。The explanation is simple:
rng:optional
is a child ofex:data
.There is no template matchin
ex:data
, therefore it is processed by the XSLT built-in template for an element node.The built-in template, of course, doesn't know anything about parameters being passed to it, so it doesn't pass them through to the next templates that it applies.
Thus, the template matching
rng:optional
(above) is selected for execution by the XSLT built-in template for elements and no parameters are passed to this selected template.Therefore, the value of the
parameter
param is the empty string and you get the correct output from both Saxon and XalanJ.