XSLT仅选择rowset中的最后一个版本元素

时间:2012-11-01 09:44:30

标签: xslt foreach unique distinct xslt-1.0

我的xml是:

<RowSet>
  <Row>
     <msg_id>1</msg_id>
     <doc_id>1</doc_id>
     <doc_version>1</doc_version>
  </Row>
  <Row>
     <msg_id>2</msg_id>
     <doc_id>1</doc_id>
     <doc_version>2</doc_version>
  </Row>
    <Row>
     <msg_id>3</msg_id>
     <doc_id>1</doc_id>
     <doc_version>3</doc_version>
  </Row>
      <Row>
     <msg_id>4</msg_id>
     <doc_id>2</doc_id>
     <doc_version>1</doc_version>
  </Row>
  <RowSet>

我需要做什么:

如果存在具有相同doc_id的行,则我需要仅选择具有较大doc_version个数字的节点。

预期产出:

 <RowSet>
    <Row>
     <msg_id>3</msg_id>
     <doc_id>1</doc_id>
     <doc_version>3</doc_version>
   </Row>
      <Row>
     <msg_id>4</msg_id>
     <doc_id>2</doc_id>
     <doc_version>1</doc_version>
  </Row>
  <RowSet>

可能会有所帮助:msg_id是唯一的,因此对于同一msg_iddoc_id更大的行会占据最后一个doc_version

3 个答案:

答案 0 :(得分:1)

与其他一些答案不同,此转换有效

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

 <xsl:key name="kRowByDocId" match="Row" use="doc_id"/>

 <xsl:template match="/*">
    <xsl:apply-templates select=
      "Row[generate-id()=generate-id(key('kRowByDocId', doc_id)[1])]"/>
 </xsl:template>

 <xsl:template match="Row">
     <xsl:for-each select="key('kRowByDocId',doc_id)">
      <xsl:sort select="doc_version" data-type="number" order="descending"/>

      <xsl:if test="position() = 1"><xsl:copy-of select="."/></xsl:if>
     </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档时:

<RowSet>
    <Row>
        <msg_id>1</msg_id>
        <doc_id>1</doc_id>
        <doc_version>1</doc_version>
    </Row>
    <Row>
        <msg_id>2</msg_id>
        <doc_id>1</doc_id>
        <doc_version>2</doc_version>
    </Row>
    <Row>
        <msg_id>3</msg_id>
        <doc_id>1</doc_id>
        <doc_version>3</doc_version>
    </Row>
    <Row>
        <msg_id>4</msg_id>
        <doc_id>2</doc_id>
        <doc_version>1</doc_version>
    </Row>
</RowSet>

产生了想要的正确结果:

<Row>
   <msg_id>3</msg_id>
   <doc_id>1</doc_id>
   <doc_version>3</doc_version>
</Row>
<Row>
   <msg_id>4</msg_id>
   <doc_id>2</doc_id>
   <doc_version>1</doc_version>
</Row>

<强>解释

  1. 正确使用 Muenchian Grouping 方法查找属于每个不同群组的一个项目。

  2. 正确使用 sorting 查找小组中的最大项目。

  3. 正确使用 key() 功能 - 选择给定群组中的所有项目。

答案 1 :(得分:0)

XSLT 1.0解决方案

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:key name="doc_id" match="RowSet/Row" use="doc_id"/>
    <xsl:template match="/">
        <xsl:for-each select="RowSet/Row[generate-id() = generate-id(key('doc_id',doc_id))]">
            <xsl:sort select="doc_id" data-type="number" order="ascending"/>

            <xsl:for-each select="../Row[doc_id = current()/doc_id]">
                <xsl:sort select="doc_version" data-type="number" order="descending"/>
                <xsl:if test="position() = 1">
                    // stuff
                </xsl:if>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

逻辑是:

  • 获取每个唯一的文档ID
  • 然后跳过一个级别并使用该doc_id
  • 遍历每个doc_version
  • 采用最高的doc_version

答案 2 :(得分:-1)

试试这个

 <xsl:for-each-group select="RowSet/RowSet" group-by="doc_id">
       <xsl:for-each select="current-group()">
       <xsl:sort select="doc_version" order="desending"/>
          <xsl:if test="position()=1">
                   // do it your stuff here
            </xsl:if>
        </xsl:for-each>
    </xsl:for-each-group>
相关问题