【问题标题】:XSL grouping outputXSL 分组输出
【发布时间】:2012-07-13 10:52:08
【问题描述】:

我有一个带有记录的 XML,一些记录相互关联,因此,我想在输出中将它们组合在一起。

XML:

<Records>
   <Record id="1" group="10" />
   <Record id="2" group="20" />
   <Record id="3" group="20" />
   <Record id="4" group="20" />
</Records>

目前,我显示

<span>1</span><span>2</span><span>3</span><span>4</span>

我想显示的是(基于具有相同组的记录)

<span>1</span><span>2-4</span>

我已经研究过使用preceding-sibling::Record/@group 来查看Records 迭代之间的分组是否发生了变化,但我正在努力弄清楚如何实现我需要的2-4 分组。

这是我到目前为止的内容,穿插了一些 cmets 来说明我正在尝试做的事情:

<xsl:for-each select="Records/Record">
   <xsl:if test="@group != preceding-sibling::Record/@group">
      <!-- obviously here we need 2-4...somehow? -->
      <span><xsl:value-of="@id" /></span>
   </xsl:if>
</xsl:for-each>

【问题讨论】:

  • 您是否使用像 Saxon 9 或 AltovaXML 这样的 XSLT 2.0 处理器,以便可以使用xsl:for-each-group select="Record" group-adjacent="@group"&gt;
  • 不幸的是它只是 XSLT 1 - 我用它来渲染浏览器
  • 看看你能不能让stackoverflow.com/questions/11451989/xsl-count-continuous-nodes/…自己适应你的需要,如果不能告诉我们,我相信以后会有人帮忙。

标签: xml xslt xslt-1.0


【解决方案1】:

这种转变

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

 <xsl:key name="kFollowing" match="Record"
  use="generate-id(preceding-sibling::*
                         [not(@group = current()/@group)
                          ][1])"/>

 <xsl:template match="/*">
       <xsl:apply-templates mode="makeGroup" select=
       "Record[not(@group = preceding-sibling::*[1]/@group)]"/>
 </xsl:template>

 <xsl:template match="Record" mode="makeGroup">
  <xsl:variable name="vGroup"
    select="key('kFollowing', generate-id(preceding-sibling::*[1]))"/>
  <span>
   <xsl:value-of select="$vGroup[1]/@id"/>
   <xsl:if test="$vGroup[2]">
    <xsl:value-of select="concat('-', $vGroup[last()]/@id)"/>
   </xsl:if>
  </span>
 </xsl:template>
</xsl:stylesheet>

应用于提供的 XML 文档时:

<Records>
    <Record id="1" group="10" />
    <Record id="2" group="20" />
    <Record id="3" group="20" />
    <Record id="4" group="20" />
</Records>

产生想要的正确结果

<span>1</span><span>2-4</span>

解释

  1. 这是位置分组,使用一个键来定义组成一个组的所有相邻记录元素。

  2. 这是一种高效(次线性)算法,因为使用了密钥。使用兄弟轴的算法通常是O(N^2)——时间复杂度是二次方的,如果兄弟N 的总数很大,则可能会太慢。

【讨论】:

    【解决方案2】:

    如果你的节点总是连续的,你可以使用一些简单的东西,比如

    <xsl:template match="/">
        <xsl:for-each select="Records/Record">
            <xsl:if test="position() = 1 or @group != preceding-sibling::Record[1]/@group">
                <span><xsl:value-of select="@id" />
                <xsl:if test="following-sibling::Record/@group = @group">
                    <xsl:variable name="following" select="following-sibling::Record[@group = ./@group]"/>
                 - <xsl:value-of select="$following[count($following)]/@id"/>
                </xsl:if>
                </span>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
    

    但如果不是,您可能需要一个递归函数来提供更强大的功能并手动计算节点数

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-26
      • 1970-01-01
      • 1970-01-01
      • 2014-07-02
      • 1970-01-01
      相关资源
      最近更新 更多