在XSLT 2.0中匹配XPath表达式中不能使用template参数?

时间:2017-10-07 20:26:40

标签: xslt xslt-2.0

根据this SO问题,应该可以在match的XPath表达式中使用参数。但是,如果要在同一模板中使用xsl:param的{​​{1}},它似乎无效。

我的XML文件如下所示

xsl:template

和我的XSL文件一样。

<?xml version="1.0" encoding="UTF-8"?>
<myRoot>
    <myNode myAttribute="3">
        <myChildAttribute myChildAttribute="a" />
    </myNode>
    <myNode myAttribute="2">
        <myChildAttribute myChildAttribute="b" />
    </myNode>
    <myNode myAttribute="1" />
</myRoot>

不幸的是,当使用SAXON 9HE运行时,它会以以下错误结束

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" encoding="UTF-8"/>

    <xsl:template match="myRoot">
        <xsl:apply-templates select="myNode">
            <xsl:sort select="@myAttribute" />
            <xsl:with-param name="myParam" select="max(myNode/@myAttribute)" />
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="myNode[node() and @myAttribute = $myParam]">
        <xsl:param name="myParam" />
            <xsl:for-each select="myChildAttribute">
INSERT INTO a(b) VALUES ('<xsl:value-of select="@myChildAttribute" />');
            </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

是否无法在相同的模板的match-XPath表达式中使用模板的参数!?

2 个答案:

答案 0 :(得分:3)

  

是否无法在模板中使用模板的参数   match-XPath表达同一个模板!?

不,当选择执行模板时,模板的匹配表达式中的任何变量/参数必须在范围内(已定义/可见)。

因为模板是XSLT指令(在全局级别定义),所以范围内(他们可以看到)的唯一变量/参数是全局级变量/参数。

只有在选择执行模板之后才会将模板的参数传递给它 - 而不是在此之前。这意味着在执行模板选择过程时,该参数的值不存在。

因此,如果要在执行过程的模板选择中使用非全局表达式,则需要在相应的select指令的xsl:apply-templates属性中提供该表达式,其中此表达式可以被评估 - 不在模板的match属性中,无法评估此表达式。

为清楚起见,以下代码更正了所提供代码中的问题

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="text" encoding="UTF-8"/>

        <xsl:template match="myRoot">
            <xsl:apply-templates select="myNode[@myAttribute = max(../myNode/@myAttribute)]">
                <xsl:sort select="@myAttribute" />
            </xsl:apply-templates>
        </xsl:template>

    <xsl:template match="myNode[node()]">
             <xsl:for-each select="myChildAttribute">
INSERT INTO a(b) VALUES ('<xsl:value-of select="@myChildAttribute" />');
            </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

在提供的XML文档上应用此转换时

<myRoot>
    <myNode myAttribute="3">
        <myChildAttribute myChildAttribute="a" />
    </myNode>
    <myNode myAttribute="2">
        <myChildAttribute myChildAttribute="b" />
    </myNode>
    <myNode myAttribute="1" />
</myRoot>

没有产生错误,这是转换的输出(我不能说“正确的输出”,因为没有定义任何要求因此无法验证。我对此有所保留代码:例如,<xsl:sort>的{​​{1}}子元素的使用没有意义,因为它将对相等(max())值进行排序,并且对相等值序列进行排序会产生相同的序列): / p>

xsl:apply-templates

答案 1 :(得分:2)

我认为这不会起作用。该参数在您定义的模板中有效。但是,匹配表达式实际上不是模板的一部分。当myParam尚未定义时,必须从外部进行评估。

您必须将max(myNode / @ myAttribute)的过滤移动到apply-templates call的select表达式。