Результат соединения XQuery

У меня есть XML, который выглядит так:

<?xml version="1.0"?>
<root>
  <flight>
    <number>10001</number>
    <airport>LAX</airport>
    <dest>
      <airport>SFO</airport>
    </dest>
  </flight>
  <flight>
    <number>10002</number>
    <airport>LAX</airport>
    <dest>
      <airport>JFK</airport>
    </dest>
  </flight>
  <flight>
    <number>10003</number>
    <airport>JFK</airport>
    <dest>
      <airport>LAX</airport>
    </dest>
  </flight>
</root>

Используя XQuery, мне нужно получить что-то вроде этого:

<res>
    <airport code="LAX">
        <deps>2</deps>
        <dests>1</deps>
    </airport>
    <airport code="JFK">
        <deps>1</deps>
        <dests>1</deps>
    </airport>
    <airport code="SFO">
        <deps>0</deps>
        <dests>1</deps>
    </airport>
</res>

Я сделал это и могу получить правильный результат, однако мой запрос может найти только deps или dests, но не оба.

Вот как я подошел к проблеме.

let $all := doc("flights.xml")/root
for $airports in distinct-values($all/flight//*/airport) (:here I get all airport codes:)
order by $airports 

for $nr-dep in $all/flight/airport

where $nr-dep = $airports 
group by $airports 

return <res>
          <airport name="{$airports}"><deps>{count($nr-dep)}</deps></airport>
       </res>

Здесь я получаю количество отправлений. Я могу легко получить адреса, заменив for $nr-dep in $all/flight/airport на for $nr-dep in $all/flight/dest/airport, однако я не могу найти способ показать оба с тем же результатом, что и ожидаемый XML.


person Enve    schedule 14.03.2016    source источник


Ответы (2)


Почему бы не просто:

for $airport in distinct-values($all//airport)
order by $airport
return <airport code="{$airport}">
  <deps>{count($all//flight/airport[. = $airport])}</deps>
  <dests>{count($all//dest/airport[. = $airport])}</dests>
</airport>
person Tomalak    schedule 14.03.2016
comment
Однако это работает, я все еще начинаю работать с XQuery и не могу понять всех деталей, стоящих за этим, и того, что заставляет его работать. Я не понимаю // и [. = $airport]. Спасибо большое. - person Enve; 14.03.2016
comment
// вызывает рекурсивный поиск по дереву, т.е. всех потомков, а не только детей. Это сокращение от descendant-or-self::node(), и это XPath, а не XQuery. [. = $value] также является XPath, это означает если этот узел имеет текстовое значение $value. Кажется, вам нужно сначала прочитать XPath. :) - person Tomalak; 14.03.2016

Вот версия с использованием group by:

<res>{
    for $airport in //airport
    group by $code := $airport/text()
    order by $code
    return <airport code="{$code}">
        <deps>{ count($airport/parent::flight) }</deps>
        <dests>{ count($airport/parent::dest) }</dests>
    </airport>
}</res>
person Leo Wörteler    schedule 14.03.2016
comment
Я думаю, было бы неплохо указать порядок сортировки после группировки. Прочитав спецификацию, я не думаю, что определенный порядок гарантируется group by. - person Tomalak; 14.03.2016
comment
Хороший вопрос, я пропустил это в исходном запросе. Я обновлю свой ответ. - person Leo Wörteler; 14.03.2016
comment
Я думаю, что это более элегантно, чем мое решение. - person Tomalak; 14.03.2016