我想创建一个可以在xml上运行的通用XSLT 2.0函数:
<?xml version="1.0"?>
<foo xmlns:my="http://meohmy.org" xmlns:yours="http://meohmy2.org">
<yours:pet my:type="dog" my:color="red">Cindy</yours:pet>
<yours:pet my:type="cat">Felix</yours:pet>
<yours:pet my:type="cat" my:color="green">Pai Mei</yours:pet>
</foo>
并给出如下函数签名:
my:doit('item',/foo/yours:/pet,@my:color)
(其中第一个参数是标签,第二个是我要报告的节点集,第三个参数是我想要为第二个参数的节点集中的每个节点输出的值,无论它是否具有它)。
我希望它返回这样的数据:
info=red;;green
请注意,我想要一个与该元素相对应的空占位符,而不是第三个参数,并且顺序很重要。
由于我在样式表中做了很多这样的事情(由于不同的原因,我做了很多次),所以函数似乎是一种自然的方式。这就是我到目前为止所提出的......
<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="http://meohmy.org"
xmlns:yours="http://meohmy2.org">
<xsl:template match="/">
<xsl:value-of select="my:doit('item',/foo/yours:pet,@my:color)"/>
</xsl:template>
<xsl:function name="my:doit" as="xs:string?">
<xsl:param name="item" as="xs:string"/>
<xsl:param name="value"/>
<xsl:param name="subvalue"/>
<xsl:if test="$value">
<xsl:value-of>
<xsl:value-of select="$item"/>
<xsl:text>=</xsl:text>
<xsl:for-each select="$value">
<xsl:value-of select="current()/$subvalue"/>
<xsl:if test="position() != last()">
<xsl:text>;</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:value-of>
</xsl:if>
</xsl:function>
</xsl:stylesheet>
但是当我这样做时,我从函数doit()得到以下值:
item=;;
这表明样式表中的<xsl:value-of select="current()/$subvalue"/>
不正确。我很亲密,我能感受到它;&gt;有什么建议吗?
谢谢!
答案 0 :(得分:1)
试试这个样式表
<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="http://meohmy.org"
xmlns:yours="http://meohmy2.org">
<xsl:template match="/">
<xsl:value-of select="my:doit('item',/foo/yours:pet,'my:color')"/>
</xsl:template>
<xsl:function name="my:doit" as="xs:string?">
<xsl:param name="item" as="xs:string"/>
<xsl:param name="value"/>
<xsl:param name="subvalue"/>
<xsl:if test="$value">
<xsl:value-of>
<xsl:value-of select="$item"/>
<xsl:text>=</xsl:text>
<xsl:for-each select="$value">
<xsl:value-of select="current()/attribute()[name() = $subvalue]"/>
<xsl:if test="position() != last()">
<xsl:text>;</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:value-of>
</xsl:if>
</xsl:function>
</xsl:stylesheet>
它给了我结果
item=red;;green
答案 1 :(得分:1)
在您的示例中,您认为您将XPath表达式作为第三个参数传递,但您不是 - 您正在传递其值。
在XPath 3.0中有一个干净的解决方案:你可以传递一个函数作为第三个参数。因此呼叫变为
select="my:doit('item', /foo/yours:pet, function($e){$e/@my:color})"
,实施变为
<xsl:function name="my:doit" as="xs:string?">
<xsl:param name="item" as="xs:string"/>
<xsl:param name="value" as="element()*/>
<xsl:param name="subvalue" as="function(element()) as xs:string?"/>
<xsl:if test="$value">
<xsl:value-of>
<xsl:value-of select="$item"/>
<xsl:text>=</xsl:text>
<xsl:value-of select="$value ! $subvalue(.)" separator=";"/>
</xsl:value-of>
</xsl:if>
</xsl:function>
如果您无法使用XPath 3.0(以上将在Saxon-PE 9.5中使用),那么替代方案是(a)使用Dimitre Novatchev的FXSL库,它模拟XSLT 2.0中的高阶函数,或者(b)不是传递函数,而是以字符串的形式传递XPath表达式,并使用xx:eval()扩展函数动态评估表达式 - 许多处理器提供这样的扩展,但它不是标准语言
(注意,在XPath 3.0中,A!B的含义基本上与“返回$ x / B中的$ x”相同)