关于xml:在XSLT函数中维护上下文

 2021-04-26 

Maintaining Context in XSLT Functions

对于以下XML:

1
2
3
4
5
6
7
8
9
10
<X12>
    <GROUP>
        <TS_850>
            <REF>
                <REF01>CR</REF01>
                <REF02>53222</REF02>
            </REF>
        </TS_850>
    </GROUP>
</X12>

此代码有效:

1
2
3
4
5
6
7
8
9
10
11
<xsl:variable name="REF02">
    <xsl:for-each select="X12/GROUP/TS_850/REF">
        <xsl:if test="REF01='CR'">
            <xsl:value-of select="REF02"/>
        </xsl:if>
    </xsl:for-each>
</xsl:variable>

...

<xsl:value-of select="$REF02"/>

但是,此代码不:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<xsl:function name="test:valueWhereValue">
    <xsl:param name="context" />
    <xsl:param name="conditionalElement" />
    <xsl:param name="conditionalValue" />
    <xsl:param name="outputElement"/>

    <xsl:for-each select="$context">
        <xsl:if test="$conditionalElement = $conditionalValue">
            <xsl:value-of select="$outputElement" />
        </xsl:if>
    </xsl:for-each>
</xsl:function>

...

<xsl:copy-of select="test:valueWhereValue(X12/GROUP/TS_850/REF, REF01, 'CR', REF02)"></xsl:copy-of>

据我所知,这两个代码段在功能上应该等效。但是,根据我的调试器的说法,REF01和REF02实际上并没有像我在函数版本中所期望的那样引用节点。似乎我实际上并未在函数中使用for-each语句输入适当的上下文,这阻止了子节点的正确选择。为什么会这样,如何修复我的功能?


仅供参考,此:

1
2
3
4
5
6
7
<xsl:variable name="REF02">
    <xsl:for-each select="X12/GROUP/TS_850/REF">
        <xsl:if test="REF01='CR'">
            <xsl:value-of select="REF02"/>
        </xsl:if>
    </xsl:for-each>
</xsl:variable>

是-理论上(*)-此:

1
<xsl:variable name="REF02" select="X12/GROUP/TS_850/REF[REF01 = 'CR']/REF02" />

(*),即每个TS_850

恰好有一个REF01等于'CR'的情况

关于您的功能,需要进行以下三个观察:

  • 对于函数调用,当前节点不会更改。您可以放心地假设.(或current())在函数内部的含义与在函数外部的含义相同。您可以使用该事实隐式传输上下文。
  • 在这个特定的函数中,您传入变量并且根本不引用上下文。所以无论如何当前节点都没关系。
  • 通常,您可能希望使用<xsl:sequence>而不是<xsl:value-of>作为返回值。序列比该函数将返回的纯字符串具有更多的通用性。

因此您的函数可能看起来像这样:

1
2
3
4
5
6
7
8
9
<xsl:function name="test:valueWhereValue">
    <xsl:param name="conditionalElement" />
    <xsl:param name="conditionalValue" />
    <xsl:param name="outputElement"/>

    <xsl:if test="$conditionalElement = $conditionalValue">
        <xsl:sequence select="$outputElement" />
    </xsl:for-each>
</xsl:function>

和这样的呼叫:

1
2
3
<xsl:template match="X12/GROUP/TS_850/REF">
    <xsl:copy-of select="test:valueWhereValue(REF01, 'CR', REF02)" />
</xsl:template>

当您退后一步时,您的功能将替换为评分者复杂的内容:

1
2
3
4
5
<xsl:template match="X12/GROUP/TS_850/REF">
    <xsl:if test="REF01 = 'CR'">
        <xsl:copy-of select="REF02" />
    </xsl:if>
</xsl:template>

这又是一个相当复杂的说法:

1
2
3
<xsl:template match="X12/GROUP/TS_850/REF[REF01 = 'CR']">
    <xsl:copy-of select="REF02" />
</xsl:template>

这又是一个相当复杂的说法:

1
<xsl:copy-of select="X12/GROUP/TS_850/REF[REF01 = 'CR']/REF02" />

因此首先具有一个毫无意义的功能。