Группы заказов, возвращаемые группой XQuery FLWOR по предложению в порядке документов

Исходя из опыта XSLT, я иногда пытаюсь найти XQuery-эквивалент некоторого подхода XSLT, к которому я привык. Этот вопрос о том, как упорядочить группы в порядке документов, что XSLT 2/3, кажется, делает автоматически, в то время как в XQuery порядок кажется неопределенным.

Более подробно: с группировкой в ​​XSLT 3 (или также 2) я привык ( https://www.w3.org/TR/xslt-30/) получать группы, возвращаемые в "порядке". первого появления ", то есть, например, когда я группирую некоторые дочерние элементы элемента, порядок групп определяется порядком документов первого элемента в каждой группе. Похоже, что это не так в XQuery, где https://www.w3.org/TR/xquery-31/ говорит: "Порядок, в котором кортежи появляются в кортеже постгруппировки поток зависит от реализации."

Короче говоря, вопрос: если

              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/) 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 я гарантированно получу результат в порядке (Italia, France, Deutschland) с входа:

<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 ответов

Другие вопросы по тегам