分组复杂的“选择”

时间:2017-09-25 16:28:18

标签: grouping xslt-2.0 xpath-2.0

这是源XML:

<root>
  <!-- a and b have the same date entries, c is different -->
  <variant name="a">
    <booking>
      <date from="2017-01-01" to="2017-01-02" />
      <date from="2017-01-04" to="2017-01-06" />
    </booking>
  </variant>
  <variant name="b">
    <booking>
      <date from="2017-01-01" to="2017-01-02" />
      <date from="2017-01-04" to="2017-01-06" />
    </booking>
  </variant>
  <variant name="c">
    <booking>
      <date from="2017-04-06" to="2017-04-07" />
      <date from="2017-04-07" to="2017-04-09" />
    </booking>
  </variant>
</root>

我想对这三种变体进行分组,以便每个日期中具有相同@from@to的每个变体都应该组合在一起。

我的尝试是:

<xsl:stylesheet version="2.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"></xsl:output>

  <xsl:template match="root">
    <variants>
    <xsl:for-each-group select="for $i in variant return $i" group-by="booking/date/@from">
      <group>
        <xsl:attribute name="cgk" select="current-grouping-key()"/>
        <xsl:copy-of select="current-group()"></xsl:copy-of>
      </group>
    </xsl:for-each-group>
    </variants>
  </xsl:template>
</xsl:stylesheet> 

但这给了太多的团体。 (如何)这可能实现?

1 个答案:

答案 0 :(得分:2)

使用composite key和XSLT 3.0,您可以使用

<xsl:template match="root">
    <variants>
        <xsl:for-each-group select="variant" group-by="booking/date/(@from, @to)" composite="yes">
            <group key="{current-grouping-key()}">
                <xsl:copy-of select="current-group()"/>
            </group>
        </xsl:for-each-group>
    </variants>
</xsl:template>

应该将具有相同后代variant元素序列的任何date元素组合在一起。

XSLT 3.0受Saxon 9.8(任何版本)或9.7(PE和EE)或2017版Altova XMLSpy / Raptor支持。

使用XSLT 2.0,您可以将所有这些日期值与string-join()

连接起来
<xsl:template match="root">
    <variants>
        <xsl:for-each-group select="variant" group-by="string-join(booking/date/(@from, @to), '|')">
            <group key="{current-grouping-key()}">
                <xsl:copy-of select="current-group()"/>
            </group>
        </xsl:for-each-group>
    </variants>
</xsl:template>

与XSLT 3.0解决方案一样,它只将variantdate个后代的序列组合在一起,我不确定这是否足够,或者您是否想要对任何date个后代进行排序首先在计算分组密钥之前。在XSLT 3中,您可以使用

轻松完成
       <xsl:for-each-group select="variant" group-by="sort(booking/date, (), function($d) { xs:date($d/@from), xs:date($d/@to) })!(@from, @to)" composite="yes">

内联(虽然因为它不支持函数表达式/高阶函数而留下9.8 HE,所以你需要将排序移动到你自己的用户定义的xsl:function并在那里使用{{1 }})。