需要 XSLT 转换来计算从应用模板返回的元素

Need XSLT transform to count elements returned from applied template

我有一个与此非常相似的问题:Need XSLT transform to remove duplicate elements - sorted by an attribute。我从最佳答案中提取了解决方案并稍作修改。我必须计算状态,但只考虑最新的结果。

我的模板如下所示:

<xsl:template match='Results/Result' mode='countstatus'>
    <xsl:param name='status' select='"Pass"'/>
    <xsl:for-each select="key('sn-key', SerialNumber)">
        <xsl:sort select='./Date' order='descending'/>
        <xsl:if test='((position() = 1) and (./Status=$status))'>
            <xsl:copy-of select="."/>
        </xsl:if>
    </xsl:for-each>
</xsl:template>

我不想显示所有匹配结果,只想显示应用此模板后返回的项目数。

我的关键定义是 <xsl:key name='sn-key' match='Results/Result' use='SerialNumber'/> 我用 <xsl:apply-templates select='Results/Result[generate-id() = generate-id(key("sn-key", SerialNumber)[1])]' mode='countstatus'/>.

调用这个模板

编辑

重新思考一下,我发现我的问题有点不清楚。这里有更多详细信息。

我的输入是这样的:

<Results>
    <Result ID="0">
        <SerialNumber>3333</SerialNumber>
        <Status>Fail</Status>
        <Date>21</Date>
    </Result>
    <Result ID="1">
        <SerialNumber>1111</SerialNumber>
        <Status>Fail</Status>
        <Date>34</Date>
    </Result>
    <Result ID="2">
        <SerialNumber>1111</SerialNumber>
        <Status>Pass</Status>
        <Date>67</Date>
    </Result>
    <Result ID="3">
        <SerialNumber>2222</SerialNumber>
        <Status>Fail</Status>
        <Date>40</Date>
    </Result>
    <Result ID="4">
        <SerialNumber>1111</SerialNumber>
        <Status>Fail</Status>
        <Date>55</Date>
    </Result>
    <Result ID="5">
        <SerialNumber>1111</SerialNumber>
        <Status>Fail</Status>
        <Date>88</Date>
    </Result>
    <Result ID="6">
        <SerialNumber>2222</SerialNumber>
        <Status>Fail</Status>
        <Date>22</Date>
    </Result>
    <Result ID="7">
        <SerialNumber>1111</SerialNumber>
        <Status>Fail</Status>
        <Date>86</Date>
    </Result>
    <Result ID="8">
        <SerialNumber>3333</SerialNumber>
        <Status>Pass</Status>
        <Date>99</Date>
    </Result>
</Results>

我想数例如Fail 状态出现了多少次,但仅考虑 SerialNumber 的最新结果。我之前展示的模板显示了 SerialNumber 的所有最新结果(但状态 Pass)。我只想显示数字。例如,在查找失败次数时,我想显示 2 而不是 [1111 Fail 88, 2222 Fail 40].

我的转型现在看起来像这样(但我还需要其他东西):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:key name='sn-key' match='Results/Result' use='SerialNumber' />

<xsl:template match="/">
    <xsl:apply-templates select="Results/Result[generate-id()=generate-id(key('sn-key', SerialNumber)[1])]"/>
</xsl:template>

<xsl:template match="Results/Result">
    <xsl:param name='status' select='"Fail"'/>
    <xsl:for-each select="key('sn-key', SerialNumber)">
        <xsl:sort select="./Date" order="descending"/>
        <xsl:if test='((position() = 1) and (./Status=$status))'>
            <xsl:value-of select="."/><br />
        </xsl:if>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

--- 根据澄清进行编辑 ---

I would like to count e.g. how many times the Fail status occurs, but considering only the latest results for SerialNumber.

我认为这可以转化为:

  • 按序列号对 Result 进行分组;
  • 计算最近 ResultStatus 个“失败”的组

具体方法取决于 Result 是否在输入中按时间顺序列出 XML。

如果答案是肯定的,您可以简单地将 Muenchian 方法修改为 select the last(而不是通常的 first) Result 在每组中,添加另一个谓词以仅保留那些 Status 为“失败”的谓词并计算此组。这是一条单线:

XSLT 1.0

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

<xsl:key name="result-by-sn" match="Result" use="SerialNumber" />

<xsl:template match="/Results">
    <output>
        <xsl:value-of select="count(Result[count(. | key('result-by-sn', SerialNumber)[last()]) = 1][Status='Fail'])"/>
    </output>
</xsl:template>

</xsl:stylesheet>

如果答案是否定的,那你只好实际进行分组排序过滤成一个变量,然后统计结果:

XSLT 1.0

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

<xsl:key name="result-by-sn" match="Result" use="SerialNumber" />

<xsl:template match="/Results">
    <xsl:variable name="temp">
        <xsl:for-each select="Result[count(. | key('result-by-sn', SerialNumber)[1]) = 1]">
            <xsl:for-each select="key('result-by-sn', SerialNumber)">
                <xsl:sort select="Date" order="descending"/>
                <xsl:if test="position()=1 and Status='Fail'">x</xsl:if>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:variable>
    <output>
        <xsl:value-of select="string-length($temp)"/>
    </output>
</xsl:template>

</xsl:stylesheet>