【问题标题】:XSLT select only last version element in rowsetXSLT 仅选择行集中的最后一个版本元素
【发布时间】:2012-11-01 09:44:30
【问题描述】:

我的 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_id 较大的行对于相同的doc_id 保留最后一个doc_version

【问题讨论】:

    标签: xslt foreach unique distinct xslt-1.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 表示没有包含“do stuff”变体的答案。 :)
    【解决方案2】:

    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

    【讨论】:

      【解决方案3】:

      试试这个

       <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>
      

      【讨论】:

      • 感谢您的回复!如果只有一个具有不同版本的文档,那么您的解决方案将是正确的,但是有许多具有 doc_version 的不同文档是 ununiqe (1,2...,n)
      • 不,你好像理解错了,for-each-group 会对每个 doc_id 进行循环。你试过这个 xsl 吗?
      • 我也不确定xslt1.0是否支持for-each-group。 xslt2.0 可用于分组。
      • 这不是一个完整的样式表,因此可能会使原始发布者感到困惑(例如,这个问题被标记为 xslt-1.0,但您提供了 2.0 解决方案)。此外,请考虑提供比"// do stuff here" 更负责任的答案。
      猜你喜欢
      • 1970-01-01
      • 2021-10-26
      • 2017-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-18
      • 2010-11-30
      • 1970-01-01
      相关资源
      最近更新 更多