用复杂的分组 "selection"
grouping with complex "selection"
这是来源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>
但这给出了太多组。 (如何)这可能实现?
使用 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>
应该将具有相同后代 date
元素序列的任何 variant
元素组合在一起。
XSLT 3.0 受 Saxon 9.8(任何版本)或 9.7(PE 和 EE)或 Altova 的 2017 版支持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 解决方案一样,它仅将 variant
与 date
后代的相同序列分组,我不确定这是否足够或者您是否想要对任何 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 落后了,因为它不支持函数 expressions/higher 排序函数,因此您需要将排序移动到您自己的用户定义 xsl:function
并在那里使用 xsl:perform-sort
).
这是来源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>
但这给出了太多组。 (如何)这可能实现?
使用 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>
应该将具有相同后代 date
元素序列的任何 variant
元素组合在一起。
XSLT 3.0 受 Saxon 9.8(任何版本)或 9.7(PE 和 EE)或 Altova 的 2017 版支持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 解决方案一样,它仅将 variant
与 date
后代的相同序列分组,我不确定这是否足够或者您是否想要对任何 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 落后了,因为它不支持函数 expressions/higher 排序函数,因此您需要将排序移动到您自己的用户定义 xsl:function
并在那里使用 xsl:perform-sort
).