使用XSLT计算嵌套子元素的数量

时间:2018-09-12 00:25:12

标签: xml xslt xpath count

我有以下xml(实际上是FIX字典的非常简化的版本):

<fix>
<messages>
    <message name='Message1'>
        <field name='Field1' />
        <component name='Component1'/>
        <group name='Group1'>
            <field name='Field2' />
        </group>
    </message>
</messages>

<components>
    <component name='Component1'>
        <field name='Field3' />
        <group name='Group2' >
                <field name='Field4' />
                <group name='Group3' >
                    <field name='Field5' />
                    <component name='Component3' />
                </group>
        </group>
        <component name='Component2' /> 
    </component>
    <component name='Component2'>
        <field name='Field6' />
    </component>
    <component name='Component3'>
        <field name='Field7'/>
    </component>  

</components>
<fields>
    .....
</fields>
</fix>

每个消息,组件或组都可以具有字段,组件和组。

我需要计算每封邮件的组数。在上面的示例中,Message1的组数为3(Group1,Group2,Group3)

1 个答案:

答案 0 :(得分:2)

我假设您要对引用的component元素中的组进行计数,此外,第一条消息中引用的component元素本身可以引用其他component元素分组。

在这种情况下,递归函数可以解决问题。

尝试使用此XSLT

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

  <xsl:output method="text" />

  <xsl:key name="components" match="components/component" use="@name" />

  <xsl:template match="/">
    <xsl:apply-templates select="//message[@name='Message1']" />
  </xsl:template>

  <xsl:template match="message">
    <xsl:value-of select="my:groupCount(.)" />
  </xsl:template>

  <xsl:function name="my:groupCount">
    <xsl:param name="node" />
    <xsl:value-of select="count($node//group) + sum($node//component/my:groupCount(key('components', @name)))" />
  </xsl:function>

</xsl:stylesheet>

http://xsltfiddle.liberty-development.net/jyH9rMP上查看它的运行情况

实际上,这不会在component1和component2都引用了component3(其中包含组)中给出正确的结果,因为它将对同一组进行两次计数。

在这种情况下,请尝试使用此XSLT

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

  <xsl:key name="components" match="components/component" use="@name" />

  <xsl:template match="/">
    <xsl:apply-templates select="//message[@name='Message1']" />
  </xsl:template>

  <xsl:template match="message">
    <xsl:value-of select="count(my:groups(.)/@name)" />
  </xsl:template>

  <xsl:function name="my:groups">
    <xsl:param name="node" />
    <xsl:sequence select="$node//group, $node//component/my:groups(key('components', @name))" />
  </xsl:function>
</xsl:stylesheet>

如果component1引用了component2,但component2引用了component1,请警惕无限循环