XSLT按2个参数排序,选择第1个唯一值和第2个最高值

时间:2015-01-27 13:04:55

标签: xml sorting variables xslt unique

我将xls书保存为xml。我有第一行标题和其他行数据。 在xml中它看起来:

<Row ss:AutoFitHeight="0">
    <Cell><Data ss:Type="String">Header 1 - id</Data><NamedCell
      ss:Name="_FilterDatabase"/></Cell>
    <Cell><Data ss:Type="String">Header 2 - Version</Data><NamedCell ss:Name="_FilterDatabase"/></Cell>
    <Cell><Data ss:Type="String">Header 3 - some data...</Data><NamedCell
      ss:Name="_FilterDatabase"/></Cell>
</Row>
<Row ss:AutoFitHeight="0">
    <Cell><Data ss:Type="String">id001</Data><NamedCell
      ss:Name="_FilterDatabase"/></Cell>
    <Cell><Data ss:Type="Number">1</Data><NamedCell ss:Name="_FilterDatabase"/></Cell>
    <Cell><Data ss:Type="String">blabla</Data><NamedCell
      ss:Name="_FilterDatabase"/></Cell>        
</Row>
<Row ss:AutoFitHeight="0">
    <Cell><Data ss:Type="String">id001</Data><NamedCell
      ss:Name="_FilterDatabase"/></Cell>
    <Cell><Data ss:Type="Number">2</Data><NamedCell ss:Name="_FilterDatabase"/></Cell>
    <Cell><Data ss:Type="String">blabla</Data><NamedCell
      ss:Name="_FilterDatabase"/></Cell>        
</Row>
<Row ss:AutoFitHeight="0">
    <Cell><Data ss:Type="String">id002</Data><NamedCell
      ss:Name="_FilterDatabase"/></Cell>
    <Cell><Data ss:Type="Number">1</Data><NamedCell ss:Name="_FilterDatabase"/></Cell>
    <Cell><Data ss:Type="String">blabla</Data><NamedCell
      ss:Name="_FilterDatabase"/></Cell>        
</Row>

所以我有两个主要字段 - 标题1和标题2,第一个包含id(不唯一!!!)第二个版本或版本。
它在Excel中看起来如何:

Number  Version
A001    1
A001    6
A002    2
A002    3
A003    1

我需要使用最高版本处理所有唯一身份证件! 在这里,我想得到

A001    6
A002    3
A003    1

我的xslt代码是:

 <xsl:template match="orig:Table" name ="Table">
    <xsl:variable name="Id" select ="'Number'"/>
    <xsl:element name="Declarations">
      <xsl:for-each select="orig:Row">
        <xsl:sort select="orig:Cell[1]/orig:Data" data-type="text" order="ascending"/>
        <xsl:sort select="orig:Cell[2]/orig:Data" data-type="number" order="descending"/>
        <xsl:if test="$Id!=orig:Cell[1]/orig:Data">
          <xsl:call-template name="Row"> <!--Here in template "Row" all further processing will be done-->
        </xsl:if>

      </xsl:for-each>
    </xsl:element>
  </xsl:template>

首先我要对它们进行排序,以获得如下列表:

Number  Version
A001    6
A001    1
A002    3
A002    2
A003    1

然后我想保存每个第一个标头值并在下一行中将它与自身进行比较 - 如果值相同,则表示它与旧版本的记录相同,我们跳过它。但是如果价值发生变化 - 这意味着我们有一个最新版本的新记录,我们应该接受它。 例如:

"Number" != A001    6 => we take this
A001 = A001 1 => skip
A001 != A002     3 => we take this
and so on

如果我可以使用内部&#34; IF&#34;那将会很容易。建设如

variable name="Id" := orig:Cell[1]/orig:Data

但这里不可能!

请帮助!

1 个答案:

答案 0 :(得分:0)

这基本上是一个分组问题 - 您尝试按行的第一个单元格值对行进行分组,然后从该组中的最新版本生成一个每组的输出行 。 XSLT 1.0中的标准方法称为 Muenchian分组,它涉及定义一个密钥,它将相关节点分组,然后使用generate-id的技巧来提取第一个每组中的节点:

 <xsl:key name="rowById" match="orig:Row" use="orig:Cell[1]/orig:Data" />

 <xsl:template match="orig:Table" name ="Table">
    <xsl:variable name="Id" select ="'Number'"/>
    <xsl:element name="Declarations">
      <!-- Muenchian grouping - one "iteration" per unique idNNN value -->
      <xsl:for-each select="orig:Row[
           generate-id() = generate-id(key('rowById', orig:Cell[1]/orig:Data)[1])]">
        <!-- sort groups by ID -->
        <xsl:sort select="orig:Cell[1]/orig:Data" data-type="text" order="ascending"/>

        <!-- for-each over the members of this group -->
        <xsl:for-each select="key('rowById', orig:Cell[1]/orig:Data)">
          <!-- find the maximum version value within this group -->
          <xsl:sort select="orig:Cell[2]/orig:Data" data-type="number" order="descending"/>
          <xsl:if test="position() = 1">
            <xsl:call-template name="Row"> <!--Here in template "Row" all further processing will be done-->
          </xsl:if>
        </xsl:for-each>
      </xsl:for-each>
    </xsl:element>
  </xsl:template>