Группы заказов, возвращаемые группой 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.