for-each-group 和排序(但忽略一些值)
for-each-group and sort (but ignore some values)
考虑这个来源 XML:
<root>
<value price="50">
<type name="bike"/>
<interesting value="no"/>
</value>
<value price="1">
<type name="car"/>
<interesting value="no"/>
</value>
<value price="123">
<type name="bike"/>
<interesting value="yes"/>
</value>
<value price="234">
<type name="bike"/>
<interesting value="yes"/>
<pedals madeof="gold" />
</value>
<value price="150">
<type name="car"/>
<interesting value="yes"/>
</value>
</root>
现在我想将所有自行车和所有汽车组合在一起,但顺序应该是价格(从便宜到昂贵)但只考虑 <interesting value="yes"/>
的自行车和汽车。
我的 XSLT 是
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="root">
<out>
<xsl:for-each-group select="value" group-by="type/@name">
<xsl:sort select="@price" data-type="number"/>
<elt>
<xsl:attribute name="grouping-key" select="current-grouping-key()"/>
<xsl:attribute name="min-price" select="@price"/>
</elt>
</xsl:for-each-group>
</out>
</xsl:template>
</xsl:stylesheet>
忽略 <interesting value="yes"/>
的过滤。结果是
<out>
<elt grouping-key="car" min-price="1"/>
<elt grouping-key="bike" min-price="50"/>
</out>
但应该是
<out>
<elt grouping-key="bike" min-price="123"/>
<elt grouping-key="car" min-price="150"/>
</out>
因为 bike[interesting/@value='yes']
比 car[interesting/@value='yes']
便宜
每种车辆可以有两种以上类型和更多条目 interesting="yes"
。
如何按价格排序,但只考虑那些“有趣”的?
只需通过添加谓词过滤 select 在 <xsl:for-each-group
中的元素 :
<xsl:for-each-group select="value[interesting/@value='yes']" group-by="type/@name">
结果是:
<?xml version="1.0" encoding="UTF-8"?>
<out>
<elt grouping-key="bike" min-price="123"/>
<elt grouping-key="car" min-price="150"/>
</out>
解决方案可能比它应该的更复杂,但这里是:
<xsl:for-each-group select="value" group-by="type/@name">
<xsl:sort select="not(empty(current-group()[interesting[@value = 'yes']]))" order="descending"/>
<xsl:sort select="(min(current-group()[interesting[@value = 'yes']]/xs:integer(@price)), min(current-group()/xs:integer(@price)))[1]" data-type="number"/>
<xsl:variable name="sorted-items" as="node()*">
<xsl:perform-sort select="current-group()">
<xsl:sort select="interesting[@value = 'yes']" order="descending"/>
<xsl:sort select="@price" data-type="number"/>
</xsl:perform-sort>
</xsl:variable>
<elt>
<xsl:attribute name="grouping-key" select="current-grouping-key()"/>
<xsl:attribute name="min-price" select="$sorted-items[1]/@price"/>
</elt>
</xsl:for-each-group>
考虑这个来源 XML:
<root>
<value price="50">
<type name="bike"/>
<interesting value="no"/>
</value>
<value price="1">
<type name="car"/>
<interesting value="no"/>
</value>
<value price="123">
<type name="bike"/>
<interesting value="yes"/>
</value>
<value price="234">
<type name="bike"/>
<interesting value="yes"/>
<pedals madeof="gold" />
</value>
<value price="150">
<type name="car"/>
<interesting value="yes"/>
</value>
</root>
现在我想将所有自行车和所有汽车组合在一起,但顺序应该是价格(从便宜到昂贵)但只考虑 <interesting value="yes"/>
的自行车和汽车。
我的 XSLT 是
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="root">
<out>
<xsl:for-each-group select="value" group-by="type/@name">
<xsl:sort select="@price" data-type="number"/>
<elt>
<xsl:attribute name="grouping-key" select="current-grouping-key()"/>
<xsl:attribute name="min-price" select="@price"/>
</elt>
</xsl:for-each-group>
</out>
</xsl:template>
</xsl:stylesheet>
忽略 <interesting value="yes"/>
的过滤。结果是
<out>
<elt grouping-key="car" min-price="1"/>
<elt grouping-key="bike" min-price="50"/>
</out>
但应该是
<out>
<elt grouping-key="bike" min-price="123"/>
<elt grouping-key="car" min-price="150"/>
</out>
因为 bike[interesting/@value='yes']
比 car[interesting/@value='yes']
每种车辆可以有两种以上类型和更多条目 interesting="yes"
。
如何按价格排序,但只考虑那些“有趣”的?
只需通过添加谓词过滤 select 在 <xsl:for-each-group
中的元素 :
<xsl:for-each-group select="value[interesting/@value='yes']" group-by="type/@name">
结果是:
<?xml version="1.0" encoding="UTF-8"?>
<out>
<elt grouping-key="bike" min-price="123"/>
<elt grouping-key="car" min-price="150"/>
</out>
解决方案可能比它应该的更复杂,但这里是:
<xsl:for-each-group select="value" group-by="type/@name">
<xsl:sort select="not(empty(current-group()[interesting[@value = 'yes']]))" order="descending"/>
<xsl:sort select="(min(current-group()[interesting[@value = 'yes']]/xs:integer(@price)), min(current-group()/xs:integer(@price)))[1]" data-type="number"/>
<xsl:variable name="sorted-items" as="node()*">
<xsl:perform-sort select="current-group()">
<xsl:sort select="interesting[@value = 'yes']" order="descending"/>
<xsl:sort select="@price" data-type="number"/>
</xsl:perform-sort>
</xsl:variable>
<elt>
<xsl:attribute name="grouping-key" select="current-grouping-key()"/>
<xsl:attribute name="min-price" select="$sorted-items[1]/@price"/>
</elt>
</xsl:for-each-group>