如何使用XSLT对同一级别的XML数据进行分组?

时间:2014-03-07 07:01:12

标签: xml xslt

我想做一个XSL转换,其中我想要小组类似的东西。

但是使用像“key”“generate-id”这样的方法,我无法做到这一点。

我将源和预期格式放在下面。

我确实看过this。因此想到将相同的例子用于简化

来源:

<Root><!-- yes, I know I don't need a 'Root' element! Legacy code... -->
  <Plans>
  <Planner id="1">
    <Plan AreaID="1"></Plan>
      <Part ID="9122" Name="foo" />
      <Part ID="9126" Name="bar" />
    <Plan AreaID="1"></Plan>
      <Part ID="8650" Name="baz" />
    <Plan AreaID="2"></Plan>
      <Part ID="215" Name="quux" />
    <Plan AreaID="1" ></Plan>
      <Part ID="7350" Name="meh" />
    </Planner>

  <Planner id="2">
    <Plan AreaID="1"></Plan>
      <Part ID="9122" Name="foo" />
      <Part ID="9126" Name="bar" />
    <Plan AreaID="1"></Plan>
      <Part ID="8650" Name="baz" />
    <Plan AreaID="2"></Plan>
      <Part ID="215" Name="quux" />
    <Plan AreaID="1" ></Plan>
      <Part ID="7350" Name="meh" />
    </Planner>
  </Plans>
</Root>

预期:

<Root><!-- yes, I know I don't need a 'Root' element! Legacy code... -->
    <Plans>
        <Planner id="1">
            <Plan AreaID="1"></Plan>
            <Part ID="9122" Name="foo" />
            <Part ID="9126" Name="bar" />
            <Part ID="8650" Name="baz" />
            <Part ID="7350" Name="meh" />
            <Plan AreaID="2"></Plan>
            <Part ID="215" Name="quux" />
        </Planner>

        <Planner id="2">
            <Plan AreaID="1"></Plan>
            <Part ID="9122" Name="foo" />
            <Part ID="9126" Name="bar" />
            <Part ID="8650" Name="baz" />
            <Part ID="7350" Name="meh" />
            <Plan AreaID="2"></Plan>
            <Part ID="215" Name="quux" />
        </Planner>
    </Plans>
</Root>

在我的情况下,由于计划和部分处于同一水平,我无法根据计划进行分组,我想做理想的事情。

1 个答案:

答案 0 :(得分:4)

让Muenchian分组在这种情况下工作的诀窍是要在特定父级而不是全局组中进行分组,这种方法是在父组件中包含一些独特的内容作为分组键的一部分。通常您会使用generate-id(..),但在这种情况下,您只需使用id之外的Planner属性即可。例如

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:strip-space elements="*" />
  <xsl:output indent="yes" />

  <xsl:key name="partByArea" match="Part"
    use="concat(../@id, '|', preceding-sibling::Plan[1]/@AreaID)" />

  <!-- identity template - copy everything as-is except when overridden -->
  <xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
  </xsl:template>

  <xsl:template match="Planner">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <!-- select the first Part in each group -->
      <xsl:apply-templates mode="group" select="Part[generate-id() =
        generate-id(key('partByArea',
         concat(current()/@id, '|', preceding-sibling::Plan[1]/@AreaID))[1])]" />
    </xsl:copy>
  </xsl:template>

  <!-- template applied to the first Part in each group -->
  <xsl:template match="Part" mode="group">
    <!-- the Plan that heads this group -->
    <xsl:apply-templates select="preceding-sibling::Plan[1]" />
    <!-- all the matching Part elements -->
    <xsl:apply-templates select="key('partByArea',
         concat(../@id, '|', preceding-sibling::Plan[1]/@AreaID))" />
  </xsl:template>
</xsl:stylesheet>

此处,我们将Part元素按其父id的{​​{1}}和最近的Planner的{​​{1}}组合在一起。