XQuery FLWOR group by子句按文档顺序返回的订单组

时间:2018-09-10 10:37:47

标签: xquery xslt-3.0 xquery-3.1

出于XSLT的背景,我有时很难找到与我习惯的某些XSLT方法等效的XQuery。这个问题是关于如何按文档顺序对组进行排序的,XSLT 2/3似乎是自动执行的,而使用XQuery时,顺序似乎是不确定的。

更详细:在XSLT 3(或2)中进行分组时,我习惯于(https://www.w3.org/TR/xslt-30/#order-of-groups)以“首次出现的顺序”获得返回的分组,例如,当我分组时元素的某些子元素,组的顺序由每个组中第一项的文档顺序确定。在XQuery中似乎不是这种情况,https://www.w3.org/TR/xquery-31/#id-group-by说:“元组在分组后元组流中出现的顺序与实现有关。”

简而言之,问题是:如果

              for $city in city
              group by $country := $city/@country
              return ...

不能保证我在XQuery中有任何订单,正在使用

              for $city at $pos in city
              group by $country := $city/@country
              order by $pos[1]
              return ...

不是在XQuery中具有“首次出现的顺序”的正确方法,就像XSLT在默认情况下一样吗?

背景:在一个简单的示例中(取自XSLT 3规范https://www.w3.org/TR/xslt-30/#grouping-examples),其中的city元素

<cities>
  <city name="Milano"  country="Italia"      pop="5"/>
  <city name="Paris"   country="France"      pop="7"/>
  <city name="München" country="Deutschland" pop="4"/>
  <city name="Lyon"    country="France"      pop="2"/>
  <city name="Venezia" country="Italia"      pop="1"/>
</cities>

必须按@country属性值分组,以汇总每个国家的@pop人口值。

一种紧凑的XSLT 3实现方式

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    expand-text="yes"
    version="3.0">

  <xsl:output method="html" indent="yes" html-version="5"/>

  <xsl:template match="cities">
      <table>
          <thead>
              <tr>
                  <th>Country</th>
                  <th>Cities</th>
                  <th>Population</th>
              </tr>
          </thead>
          <tbody>
              <xsl:for-each-group select="city" group-by="@country">
                  <tr>
                      <td>{ current-grouping-key() }</td>
                      <td>
                          <xsl:value-of select="sort(current-group()/@name)" separator=", "/>
                      </td>
                      <td>{ sum(current-group()/@pop) }</td>
                  </tr>
              </xsl:for-each-group>
          </tbody>
      </table>
  </xsl:template>

</xsl:stylesheet>

并且我认为使用兼容的XSLT 3实现,可以保证从输入中按顺序(ItaliaFranceDeutschland)获得结果:

<table>
   <thead>
      <tr>
         <th>Country</th>
         <th>Cities</th>
         <th>Population</th>
      </tr>
   </thead>
   <tbody>
      <tr>
         <td>Italia</td>
         <td>Milano, Venezia</td>
         <td>6</td>
      </tr>
      <tr>
         <td>France</td>
         <td>Lyon, Paris</td>
         <td>9</td>
      </tr>
      <tr>
         <td>Deutschland</td>
         <td>München</td>
         <td>4</td>
      </tr>
   </tbody>
</table>

但是使用XQuery,我想我不能保证使用

declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";

declare option output:method 'html';
declare option output:html-version '5';

    cities/<table>
              <thead>
                  <tr>
                      <th>Country</th>
                      <th>Cities</th>
                      <th>Population</th>
                  </tr>
              </thead>
              <tbody>
                  {
                      for $city in city
                      group by $country := $city/@country
                      return
                          <tr>
                              <td>{ $country }</td>
                              <td>{ string-join( sort($city/@name/string()), ', ') }</td>
                              <td>{ sum($city/@pop) }</td>
                          </tr>
                  }
              </tbody>
          </table>

https://xqueryfiddle.liberty-development.net/b4GWV7的撒克逊人给出的结果为

<table>
   <thead>
      <tr>
         <th>Country</th>
         <th>Cities</th>
         <th>Population</th>
      </tr>
   </thead>
   <tbody>
      <tr>
         <td>Deutschland</td>
         <td>München</td>
         <td>4</td>
      </tr>
      <tr>
         <td>Italia</td>
         <td>Milano, Venezia</td>
         <td>6</td>
      </tr>
      <tr>
         <td>France</td>
         <td>Lyon, Paris</td>
         <td>9</td>
      </tr>
   </tbody>
</table>

确保使用XQuery中“首次出现的顺序”中的顺序的正确方法是使用

              for $city at $pos in city
              group by $country := $city/@country
              order by $pos[1]
              return
                  <tr>
                      <td>{ $country }</td>
                      <td>{ string-join( sort($city/@name/string()), ', ') }</td>
                      <td>{ sum($city/@pop) }</td>
                  </tr>

正确或最简单,最紧凑的方式?

似乎可以在https://xqueryfiddle.liberty-development.net/b4GWV7/1上完成这项工作,但是我想知道XQuery是否有其他方法,更惯用了。

0 个答案:

没有答案