【问题标题】:xslt gmuenchian grouping with sub-groups带有子组的 xslt gmuenchian 分组
【发布时间】:2016-10-26 08:16:39
【问题描述】:

我正在尝试将 xml 数据重组为组和子组。我能够让它工作,但我的代码必须包含一些东西,看起来(至少对我来说)像一个解决方法。这是我的示例文件:

数据.xml:

<data>
    <record Group="g1" SubGroup="sg1">Record 1</record>
    <record Group="g2" SubGroup="sg1">Record 2</record>
    <record Group="g1" SubGroup="sg1">Record 3</record>
    <record Group="g2" SubGroup="sg1">Record 4</record>
    <record Group="g2" SubGroup="sg2">Record 5</record>
    <record Group="g1" SubGroup="sg2">Record 6</record>
</data>

样式表.xsl:

<?xml version="1.0" encoding="UTF-8"?>

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

    <xsl:output method="xml" version="1.0" indent="yes" encoding="UTF-8"/>

    <xsl:key name="Group"    match="record" use="@Group" />
    <xsl:key name="SubGroup" match="record" use="@SubGroup" />

    <xsl:template match="/data">
        <xsl:variable name="Records" select="record"/>

        <data>
            <xsl:for-each select="$Records[generate-id(.)=generate-id(key('Group',@Group)[1])]">
                <xsl:sort select="@Group"/>
                <xsl:variable name="Group" select="@Group"/>

                <xsl:call-template name="Group">
                    <xsl:with-param name="Records" select="$Records[@Group = $Group]"/>
                    <xsl:with-param name="Group" select="$Group"/>
                </xsl:call-template>
            </xsl:for-each>
        </data>
    </xsl:template>

    <xsl:template name="Group">
        <xsl:param name="Records"/>
        <xsl:param name="Group"/>

        <group name="{$Group}">
            <xsl:for-each select="$Records[generate-id(.)=generate-id(key('SubGroup',@SubGroup)[1])]">
<!-- this works:    <xsl:for-each select="$Records[generate-id(.)=generate-id(key('SubGroup',@SubGroup)[@Group = $Group][1])]"> -->
                <xsl:sort select="@SubGroup"/>
                <xsl:variable name="SubGroup" select="@SubGroup"/>

                <xsl:call-template name="SubGroup">
                    <xsl:with-param name="Records" select="$Records[@SubGroup = $SubGroup]"/>
                    <xsl:with-param name="Group" select="$Group"/>
                    <xsl:with-param name="SubGroup" select="$SubGroup"/>
                </xsl:call-template>
            </xsl:for-each>
        </group>
    </xsl:template>

    <xsl:template name="SubGroup">
        <xsl:param name="Records"/>
        <xsl:param name="Group"/>
        <xsl:param name="SubGroup"/>

        <subgroup name="{$SubGroup}">
            <xsl:for-each select="$Records">
                <xsl:copy-of select="."/>
            </xsl:for-each>
        </subgroup>
    </xsl:template>

</xsl:stylesheet>

这是生成的输出:

<?xml version="1.0" encoding="UTF-8"?>
<data>
  <group name="g1">
    <subgroup name="sg1">
      <record Group="g1" SubGroup="sg1">Record 1</record>
      <record Group="g1" SubGroup="sg1">Record 3</record>
    </subgroup>
  </group>
  <group name="g2">
    <subgroup name="sg2">
      <record Group="g2" SubGroup="sg2">Record 5</record>
    </subgroup>
  </group>
</data>

但这是输出,我想要:

<?xml version="1.0" encoding="UTF-8"?>
<data>
  <group name="g1">
    <subgroup name="sg1">
      <record Group="g1" SubGroup="sg1">Record 1</record>
      <record Group="g1" SubGroup="sg1">Record 3</record>
    </subgroup>
    <subgroup name="sg2">
      <record Group="g1" SubGroup="sg2">Record 6</record>
    </subgroup>
  </group>
  <group name="g2">
    <subgroup name="sg1">
      <record Group="g2" SubGroup="sg1">Record 2</record>
      <record Group="g2" SubGroup="sg1">Record 4</record>
    </subgroup>
    <subgroup name="sg2">
      <record Group="g2" SubGroup="sg2">Record 5</record>
    </subgroup>
  </group>
</data>

问题在于名为“Group”的模板中的 for-each 循环。看来,key() 函数不适用于 $Records 中包含的节点,而是适用于整个输入 XML 文件。

我使用 xsltproc 和 saxon 得到相同的结果,所以我不认为这是我的 xslt 处理器中的错误。看来,我没有完全理解 key() 的工作原理。

如果我在 key() 的输出中添加一个额外的选择器 [@Group = $Group],我会得到预期的结果。

谁能解释发生了什么以及为什么需要额外的选择器[@Group = $Group]

马里奥

【问题讨论】:

标签: xslt key muenchian-grouping


【解决方案1】:

当要进行分组时,需要使用主组和子组的串联键

 <xsl:key name="SubGroup" match="record" use="concat(@Group,'|', @SubGroup)" />

然后,就像以前一样使用它,使用连接

<xsl:for-each select="$Records[generate-id(.)=generate-id(key('SubGroup',concat(@Group,'|', @SubGroup))[1])]">

试试这个 XSLT(我还简化了它,以便在使用记录调用命名模板时使用密钥)

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

    <xsl:output method="xml" version="1.0" indent="yes" encoding="UTF-8"/>

    <xsl:key name="Group"    match="record" use="@Group" />
    <xsl:key name="SubGroup" match="record" use="concat(@Group,'|', @SubGroup)" />

    <xsl:template match="/data">
        <data>
            <xsl:for-each select="record[generate-id(.)=generate-id(key('Group',@Group)[1])]">
                <xsl:sort select="@Group"/>

                <xsl:call-template name="Group">
                    <xsl:with-param name="Records" select="key('Group',@Group)"/>
                </xsl:call-template>
            </xsl:for-each>
        </data>
    </xsl:template>

    <xsl:template name="Group">
        <xsl:param name="Records"/>

        <group name="{@Group}">
            <xsl:for-each select="$Records[generate-id(.)=generate-id(key('SubGroup',concat(@Group,'|', @SubGroup))[1])]">
                <xsl:sort select="@SubGroup"/>

                <xsl:call-template name="SubGroup">
                    <xsl:with-param name="Records" select="key('SubGroup',concat(@Group,'|', @SubGroup))"/>
                </xsl:call-template>
            </xsl:for-each>
        </group>
    </xsl:template>

    <xsl:template name="SubGroup">
        <xsl:param name="Records"/>
        <subgroup name="{@SubGroup}">
            <xsl:for-each select="$Records">
                <xsl:copy-of select="."/>
            </xsl:for-each>
        </subgroup>
    </xsl:template>

</xsl:stylesheet>

【讨论】:

  • 非常感谢您的回答。您使用 key 和 concat() 和 key() 来选择参数真的很酷。但我还是不明白,为什么我必须在内部循环中考虑@Group,因为$Records 已经被简化为只包含当前组的记录。
  • @MarioKlebsch 因为正如您正确推测的那样,键(在 XSLT 1.0 中)在整个文档中都有效。
  • @michael.hor257k 正如你所说,我总结得很正确,但直到现在,我才意识到这一点。非常感谢。
猜你喜欢
  • 2012-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-13
  • 2021-12-21
  • 2016-04-23
  • 1970-01-01
相关资源
最近更新 更多