XSLT将排序后的数据拆分为不同的表

时间:2013-08-08 13:09:22

标签: sorting xslt xslt-1.0 muenchian-grouping

我正在尝试将我的xml数据格式化为两个HTML表格。我成功地可以对一些虚拟数据xls进行排序:排序,但我不能将排序后的数据拆分成不同的表。

我的xml:

<a>
    <b id="N">text1</b>
    <b id="N">text2</b>
    <b id="N+1">text3</b>
    <b id="N">text4</b>
    <b id="N+2">text5</b>
    <b id="N+3">text6</b>
    <b id="N">text7</b>
    <b id="N+2">text8</b>
</a>

N在这种情况下是一个数字,但我不知道是哪个数字。它可以是2和55,3和4,44和52以及78和98.

我希望将每个号码发送到他们自己的表中,结果将是:

<table>
    <tr><td>text1</td></tr>
    <tr><td>text2</td></tr>
    <tr><td>text4</td></tr>
    <tr><td>text7</td></tr>
</table>

<table>
    <tr><td>text3</td></tr>
</table>

<table>
    <tr><td>text5</td></tr>
    <tr><td>text8</td></tr>
</table>

<table>
    <tr><td>text6</td></tr>
</table>

如何根据属性将排序后的数据分成不同的表?

任何指针都将不胜感激。

1 个答案:

答案 0 :(得分:2)

XSLT 1.0中针对此类问题的标准方法称为 Muenchian分组。您可以定义一个键,以您希望的方式对目标元素进行分组

<xsl:key name="bsById" match="b" use="@id" />

然后使用generate-id的技巧仅提取每个组中的第一个节点作为整个组的代理

<xsl:apply-templates select="b[generate-id()
                             = generate-id(key('bsById', @id)[1])]"
                     mode="group">
  <xsl:sort select="@id" />
</xsl:apply-templates>

现在,每个组都会触发以下模板,您可以使用其中的key函数来所有组中的节点

<xsl:template match="b" mode="group">
  <table>
    <!-- extract all the nodes that are grouped with this one -->
    <xsl:apply-templates select="key('bsById', @id)">
      <!-- you could <xsl:sort> here if you want to sort within groups -->
    </xsl:apply-templates>
  </table>
</xsl:template>

<xsl:template match="b">
  <tr><td>...</td></tr>
</xsl:template>

如果该示例是您的整个XML文档,则上述所有内容都可以,但如果文档中有多个a元素,每个元素都有自己的b元素集,需要独立分组,那么关键需要更复杂。这里通常的技巧是使用父generate-id节点的a作为其b子项的分组键值的一部分:

<xsl:key name="bsByParentAndId" match="a/b" use="concat(generate-id(..), '|', @id)" />

和Muenchian分组表达

<xsl:template match="a">
  <xsl:apply-templates select="b[generate-id()
                               = generate-id(key('bsByParentAndId', concat(
                                   generate-id(current()), '|', @id))[1])]"
                       mode="group"/>
</xsl:template>

对于记录,如果您可以使用XSLT 2.0,那么它变得非常容易。无需定义复杂的密钥,只需使用for-each-group

即可
<xsl:template match="a">
  <xsl:for-each-group select="b" group-by="@id">
    <xsl:sort select="current-grouping-key()" />
    <table>
      <xsl:apply-templates select="current-group()" />
    </table>
  </xsl:for-each-group>
</xsl:template>

<xsl:template match="b">
  <tr><td>...</td></tr>
</xsl:template>