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>