回答另一个线程(参见stackoverflow: generate css color schemes)我遇到了下面的问题,其中不同的xsl引擎似乎需要不同的方法将结果树片段转换为节点集。
简化问题(但请参阅上面的链接以了解此背后的完整故事),我希望有一个包含颜色值列表的内联树。由于必须在Xpath表达式中使用,我必须专门为MSXML x.x xsl引擎创建一个节点集(内置的XML Spy在解释构造为rtf的变量的Xpath表达式时遇到的麻烦较少)。
又一个帖子stackoverflow: automating-exsltnode-set帮助了我。
生成的节点集用于从输入XML创建新变量rtf
同样,MSXML在Xpath表达式中使用新变量时会抱怨,所以我使用了node-set函数从中创建了一个节点集。
到目前为止一直很好,MSXML x.x不再出错。
但是当我在XML Spy内置或Saxon 9he中运行相同时,我得到另一个错误:似乎节点集函数未知:
Cannot find a matching 1-argument function named {urn:schemas-microsoft-com:xslt}node-set() in variable colorList
请注意,在这个特定的例子中不需要这个两步法,但正如我所说的,我简化了一些事情;我只想知道如何编写一个适用于所有xsl引擎的XSLT 1.0转换。
我使用的XSLT:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:std="http://whatever"
xmlns:exslt="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="std exslt">
<xsl:output method="xml" indent="yes"/>
<std:colors>
<color>#0000FF</color>
<color>#FF0000</color>
</std:colors>
<xsl:variable name="colors" select="document('')/*/std:colors"/>
<xsl:variable name="std:colorList">
<xsl:for-each select="//testid">
<xsl:variable name="pos" select="position() mod 2"/>
<xsl:element name="color">
<xsl:attribute name="testid"><xsl:value-of select="."/></xsl:attribute>
<xsl:value-of select="$colors/color[$pos + 1]"/>
</xsl:element>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="colorList" select="exslt:node-set($std:colorList)"/>
<xsl:template match="/">
<output>
<xsl:copy-of select="$colorList/color"/>
</output>
</xsl:template>
</xsl:stylesheet>
输入文件:
<?xml version="1.0" standalone="yes"?>
<NewDataSet>
<defects>
<testid>111</testid>
</defects>
<defects>
<testid>999</testid>
</defects>
</NewDataSet>
MSXML 3.0 / 4.0 / 6.0中的结果:
<?xml version="1.0" encoding="UTF-16"?>
<output>
<color testid="111">#FF0000</color>
<color testid="999">#0000FF</color>
</output>
结果Saxon9he:
Cannot find a matching 1-argument function named {urn:schemas-microsoft-com:xslt}node-set()
in variable colorList
导致XML Spy内置xsl引擎:
Error in XPath expression
Unknown function - Name and number of arguments do not match any function signature in the static context - 'urn:schemas-microsoft-com:xslt:node-set'
答案 0 :(得分:6)
对于MSXML以外的处理器,请使用exslt:node-set()函数。 (http://www.exslt.org/)。 (将exslt前缀绑定到函数的Microsoft版本有点奇怪 - 让我困惑了一段时间!)
您可以使用function-available()来测试哪些功能可用:
<xsl:choose>
<xsl:when test="function-available('exslt:node-set')"...
<xsl:when test="function-available('msxsl:node-set')"...
对于Saxon-HE和其他XSLT 2.0处理器,您不需要任何这些功能,因此请使用
<xsl:when test="xsl:version='2.0'">
答案 1 :(得分:4)
避免必须
<xsl:choose>
<xsl:when test="function-available('exslt:node-set')"...
每次需要时,你都可以为xslt2引擎定义 exslt节点集(使用xsl:function)和msxml(使用msxsl:script),然后只使用exslt:node-set function在你的文件的其余部分。
http://dpcarlisle.blogspot.co.uk/2007/05/exslt-node-set-function.html
向您展示如何为msxml和xslt2引擎定义它,你可以xsl:包含样式表
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exslt="http://exslt.org/common"
>
<xsl:function name="exslt:node-set">
<xsl:param name="rtf"/>
<xsl:sequence select="$rtf"/>
</xsl:function>
<xsl:stylesheet>
XSLT1的前向兼容性规则意味着包含它是安全的,XSLT1引擎只会忽略它。
答案 2 :(得分:1)
Saxon 9是一个XSLT 2.0处理器和XSLT 2.0,其中一个主要的改进是节点集和结果树片段之间的区别已经消失,你根本不需要任何扩展功能,因为你没有需要再强迫任何胁迫。 因此,使用针对任何XSLT 2.0处理器的样式表,您应该放弃任何尝试使用这样的扩展函数,然后样式表将起作用。 如果你想用XSLT 1.0和2.0处理器运行相同的样式表,那么我看到一个问题,但我不认为有一个简单的解决方案。您需要使用http://www.w3.org/TR/xslt#function-function-available和system-property来区分处理器和扩展功能的可用性。
答案 3 :(得分:1)
Microsoft的.NET XsltCompiledTransform
XSLT处理器支持exslt:node-set()。
对于MSXML,可以使用我自己的EXSLT函数子集实现 - 用于MSXML。您可以在此处找到详细说明和下载链接:
答案 4 :(得分:-1)
嗯,你可以轻松地做到这一点而无需任何检查。只需按照此处描述的模式: http://dpcarlisle.blogspot.co.uk/2007/05/exslt-node-set-function.html
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exslt="http://exslt.org/common"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="exslt msxsl">
<msxsl:script language="JScript" implements-prefix="exslt">
this['node-set'] = function (x) {
return x;
}
</msxsl:script>
<xsl:variable name="x">
<y/>
</xsl:variable>
<xsl:template match="x">
<html>
<head><title>test exslt node set</title></head>
<body>
<xsl:apply-templates select="exslt:node-set($x)/*"/>
</body>
</html>
</xsl:template>
<xsl:template match="y">
<p>node set!</p>
</xsl:template>
</xsl:stylesheet>
它肯定适用于FF,Chrome和IE7 +