计算XSLT中与深度无关的不同项

时间:2010-07-15 14:53:26

标签: xslt counting distinct-values xslt-grouping

如果我运行以下XSLT代码:

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

 <xsl:key name="kValueByVal" match="variable_name/@value"
  use="."/>

 <xsl:template match="assessment">
  <xsl:for-each select="
   /*/*/variable/attributes/variable_name/@value
             [generate-id()
             =
              generate-id(key('kValueByVal', .)[1])
             ]
   ">
     <xsl:value-of select=
     "concat(., ' ', count(key('kValueByVal', .)), '&#xA;')"/>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

关于以下XML:

<assessment>
    <variables>
        <variable>
            <attributes>
                <variable_name value="FRED"/>
            </attributes>
        </variable>
    </variables>
    <variables>
        <variable>
            <attributes>
                <variable_name value="MORTIMER"/>
            </attributes>
        </variable>
    </variables>
    <variables>
        <variable>
            <attributes>
                <variable_name value="FRED"/>
            </attributes>
        </variable>
    </variables>
</assessment>

我得到了所需的输出:

FRED 2
MORTIMER 1

(如果您愿意,请参阅my original question了解更多信息。)

但是,如果我在此输入上运行它:

<ExamStore>
    <assessment>
        <variables>
            <variable>
                <attributes>
                    <variable_name value="FRED"/>
                </attributes>
            </variable>
        </variables>
        <variables>
            <variable>
                <attributes>
                    <variable_name value="MORTIMER"/>
                </attributes>
            </variable>
        </variables>
        <variables>
            <variable>
                <attributes>
                    <variable_name value="FRED"/>
                </attributes>
            </variable>
        </variables>
    </assessment>
</ExamStore>

我一无所获。 (注意,我只是将原始输入包装在ExamStore标签中。)我期待并希望获得相同的输出。

为什么不呢?如何更改原始XSLT代码以获得相同的输出?

3 个答案:

答案 0 :(得分:1)

您的选择xpath /*/*/variable/attributes/variable_name/...不再正确,因为您在节点树中添加了另一个更高的节点。

如果你想拥有真正的独立性,你需要使用类似的东西:

//variable/attributes/variable_name/...

...(不是开头的双斜线),但这是相当危险的,因为它会捕捉到该结构的所有出现 - 确实是你的意思。

否则,只需将xpath添加到另一个/*

答案 1 :(得分:1)

当你在XML文档中引入了另一个级别时,这搞砸了原始解决方案中使用的绝对XPath表达式(完全在原始XML文件之后)。

因此,为了使XPath表达式在新的情况下工作,只需执行以下操作:

<强>替换

/*/*/variable/attributes/variable_name/@value 

<强>与

/*/*/*/variable/attributes/variable_name/@value

现在你又得到了想要的整洁结果:

FRED 2
MORTIMER 1

我永远不会给你一个“独立”的解决方案,因为你没有提供任何关于你想要应用转换的可能XML文档集的属性/保证/约束。

在您使用的原始问题中:

.//variables/variable/attributes/variable_name

关闭assessment

这就是我在我的解决方案中使用绝对XPath表达式的原因。无法保证在另一个XML文档中不会存在某些variable_name元素,因此它们的祖先链不是variables/variable/attributes,如果是这种情况,这意味着您可能对此不感兴趣这种“不规则”variable_name元素的价值。

课程是在定义问题时不应过于具体,然后需要一般解决方案。 :)

答案 2 :(得分:0)

对于真实结构独立性,您应该使用:

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

 <xsl:key name="kValueByVal" match="variable_name/@value"
  use="."/>

 <xsl:template match="variable_name[@value
             [generate-id()
             =
              generate-id(key('kValueByVal', .)[1])
             ]]">
     <xsl:value-of select=
     "concat(@value, ' ', count(key('kValueByVal', @value)), '&#xA;')"/>
 </xsl:template>
</xsl:stylesheet>

第一次输入的结果:

FRED 2
MORTIMER 1

第二次输入结果:

FRED 2
MORTIMER 1

注意:切勿将//用作fisrt XPath运算符。