XQuery получает положение узла относительно только братьев и сестер с тем же именем тега

Я пытаюсь добавить атрибут к тегу в XQuery, который соответствует его положению, но только относительно родственных элементов с тем же именем тега. В частности, элементы в списке. Итак, вот 2 возможных результата запроса:

<list>
    <title>foo</title>
    <item>bar1</item>
    <item>bar2</item>
</list>

 <list>
     <item>bar1</item>
     <item>bar2</item>
</list>

И для обоих вот желаемый результат при добавлении атрибута:

<list>
    <title>foo</title>
    <item position="1">bar1</item>
    <item position="2">bar2</item>
</list>

 <list>
     <item position="1">bar1</item>
     <item position="2">bar2</item>
</list>

Текущий запрос, который я использую:

count($item/preceding-sibling::*)+1

Но тогда подсчет включает все теги, а не только item. Итак, в приведенном выше примере с тегом title это учитывается, поэтому я получаю:

<list>
    <title>foo</title>
    <item position="2">bar1</item>
    <item position="3">bar2</item>
</list>

Я пробовал несколько вещей, таких как вычитание количества всех дочерних элементов списка, у которых нет имени тега item, например:

    count($item/preceding-sibling::*)+1-count($list/*[local-name() != 'item'])

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

РЕДАКТИРОВАТЬ:

Вот контекстуальный пример того, как я это делаю. Входные данные:

<LIST1>
    <TITLE>REASON FOR REVISION</TITLE>
    <L1ITEM KEY="L1I10254244923043">
        <PARA>Summary - Background: Updated and added related references.</PARA>
    </L1ITEM>
    <L1ITEM KEY="L1I20300231297755">
        <PARA>Summary - Action: Updated to add more work and new groups and configurations.</PARA>
    </L1ITEM>
</LIST1>

Затем я передаю корневой элемент LIST1 в эту функцию:

declare function local:listx($listx as element()){
   <list level="{substring(name($listx),5)}">
   {
     for $lxitem in $listx/*
     return if (name($lxitem) = "TITLE") then (
       <title>{local:concatText($lxitem)}</title>
     )
     else local:extract($lxitem, "item", [
       ["position", count($lxitem/preceding-sibling::*)+1]
     ])
   }
   </list>
};

Функция concatText просто объединяет весь текст с разделителем-пробелом, с этим проблем нет. Функция extract() выглядит следующим образом:

declare function local:extract(
  $root as element(), $tag as xs:string, $props as array(*)
) {
  element {$tag}{

    for $prop at $i in $props
    where array:size($prop) != 0
    return attribute {$props($i)(1)} {$prop($i)(2)},

    for $child in $root/*
    return switch(name($child))
      case "TXTGRPHC" return local:plaintext($child)
      case "PARA" return local:plaintext($child)
      case ...
      default return ()

  }
};

В качестве примечания, способ, которым я добавляю атрибуты здесь, со всем 2D-массивом $props, всегда добавляет только первый атрибут, остальные игнорируются. Хотя это другая проблема.


person Jayce444    schedule 10.04.2018    source источник
comment
просто посчитайте предшествующий элемент item; count($item/preceding-sibling::item)+1?   -  person har07    schedule 10.04.2018
comment
Пробовали, у всех получается position="1".   -  person Jayce444    schedule 10.04.2018
comment
Я не понимаю, почему подсчет preceding-sibling::item не должен работать, вы можете отредактировать свой вопрос и показать минимальные, но полные образцы.   -  person Martin Honnen    schedule 10.04.2018
comment
Жаль, что вы не можете использовать XSLT, где это поведение по умолчанию для <xsl:number/>.   -  person Michael Kay    schedule 10.04.2018
comment
На самом деле я передаю XML, полученный в результате этого XQuery, в Apache FO вместе с файлом XSL. Поэтому я рассмотрю возможность использования XSLT <xsl:number/>. Хотя сначала хотелось бы попытаться выяснить, почему мой XQ ведет себя странно. Спасибо.   -  person Jayce444    schedule 10.04.2018


Ответы (1)


При использовании BaseX вы можете использовать обновление XQuery http://docs.basex.org/wiki/XQuery_Update, например

copy $items := <root>
<list>
    <title>foo</title>
    <item>bar1</item>
    <item>bar2</item>
</list>

 <list>
     <item>bar1</item>
     <item>bar2</item>
</list>
</root>
modify (
for $item in $items/list/item
return insert node attribute {'id'} {count($item/(., preceding-sibling::item))} into $item
)
return $items

Результат

<root>
  <list>
    <title>foo</title>
    <item id="1">bar1</item>
    <item id="2">bar2</item>
  </list>
  <list>
    <item id="1">bar1</item>
    <item id="2">bar2</item>
  </list>
</root>
person Martin Honnen    schedule 10.04.2018
comment
Я добавил простой контекстный пример данных/функций, которые я использую. Попробую ваш метод, спасибо. - person Jayce444; 10.04.2018