Украсьте источник данных XML в XQuery

Я использую BaseX, который реализует XQuery 3.0.

Как украсить источник данных XML в XQuery, не печатая все элементы, которые я хочу включить? Например, рассмотрим следующий XML:

<X>
  <name>The root</name>
  <Y>
     <name> Level 1</name>
     <Z>
         <name>Level 2a</name>
         <value>1</value>
     </Z>
  </Y>
  <Y>
     <name>Level 1b</name>
     <Z>
         <name>Level 2b</name>
         <value>2</value>
     </Z>
  </Y>
</X>

Я хочу добавить сумму всех значений на каждом уровне, например:

<X>
  <name>The root</name>
  <value>3</value>
  <Y>
     <name> Level 1</name>
     <value>1</value>
     <Z>
         <name>Level 2a</name>
         <value>1</value>
     </Z>
  </Y>
  <Y>
     <name>Level 1b</name>
     <value>2</value>
     <Z>
         <name>Level 2b</name>
         <value>2</value>
     </Z>
  </Y>
</X>

Я могу использовать XQuery для этого:

for $x in /X
return
<X>{
  $x/name,
  <value>{sum($x//value)}</value>,
  for $y in $x/Y
  return
  <Y>{
    $y/name,
    <value>{sum($y//value)}</value>,
    $y/Z
  }</Y>
}</X>

Но это очень быстро утомляет, когда у меня есть много элементов, которые я должен повторить. Есть ли способ получить этот результат без необходимости вводить все атрибуты и элементы, которые я хочу сохранить в наборе результатов?


person wvdz    schedule 26.03.2016    source источник


Ответы (1)


Что вы можете! XQuery довольно мощный. Более того, BaseX поддерживает не только XQuery 3.0, но и XQuery Update, что, как мне кажется, здесь даже более актуально.

XQuery сам по себе является просто языком запросов. Поэтому, если вы хотите вставлять элементы в определенные места, вам всегда нужно воссоздавать весь элемент, как в вашем примере. Однако XQuery Update добавляет конструкции для фактического обновления документов, например. вы можете использовать это для обновления значений в базе данных. Если вы просто хотите локально преобразовать значение, существует выражение преобразования.

Поскольку конструкция для этого в спецификации довольно громоздка, мы ввели специфическое для BaseX ключевое слово update, которое можно использовать для преобразования XML-документа.

Таким образом, используя это, ваш запрос может выглядеть так:

./X update (
  insert node <value>{sum(.//value)}</value> after ./name,
  for $y in ./Y
  return insert node <value>{sum($y//value)}</value> after $y/name
)

Конечно, в зависимости от того, как повторяются ваши элементы (это совершенно ясно из вашего вопроса), теперь вы можете использовать это, например. рекурсивно вставить такой узел в соответствующие места. Еще один совет для этого: если вы хотите динамически выбирать элемент, иногда необходимо написать вместо /X лучше /*[local-name() = 'X'], так как теперь имя элемента не должно быть статичным.

person dirkk    schedule 26.03.2016
comment
Круто, мне начинает нравиться этот xquery :) - person wvdz; 26.03.2016
comment
Вы имеете в виду, добавляя их рекурсивно, что я могу написать <value>{sum($something//value)}</value> один раз и использовать его рекурсивно? Не могли бы вы добавить пример того, как это сделать для этого примера данных, если вы это имели в виду? В моей ситуации мне нужно добавить агрегаты примерно для 15 значений для нескольких уровней, поэтому было бы здорово, если бы я мог сделать это таким образом, чтобы мне нужно было написать агрегатный код только один раз. - person wvdz; 27.03.2016