группы заказов, возвращаемые группой XQuery FLWOR по предложению в порядке документов - PullRequest
0 голосов
/ 10 сентября 2018

Исходя из опыта XSLT, я иногда пытаюсь найти XQuery-эквивалент некоторого подхода XSLT, к которому я привык. Этот вопрос о том, как упорядочить группы в порядке документов, что 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 я гарантированно получу результат в следующем порядке (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>

Saxon на 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.

...