Как преобразовать текст внутри узла в дочерний узел с помощью обновления xquery?

У меня есть XML-документ, например

<root>
  <first>
    First Level
    <second>
      second level
       <third>
         Third Level
       </third>
    </second>
    <second2>
      another second level
    </second2>
  </first>
</root>

Как преобразовать этот документ со всеми узлами, то есть, если узел содержит text и child node, преобразовать текст в дочерний узел (скажем, childtext) с помощью xquery-update

<root>
  <first>
    <childtext>First Level</childtext>
    <second>
      <childtext>second level</childtext>
       <third>
         Third Level
       </third> 
    </second>
    <second2>
      another second level
    </second2>
  </first>
</root>

И вот что я пробовал:

let $a :=
<root>
  <first>
    First Level
    <second>
      second level
       <third>
         Third Level
       </third>
    </second>
    <second2>
      another second level
    </second2>
  </first>
</root>
return 
copy $i := $a
modify (
  for $x in $i/descendant-or-self::*
  return (
    if($x/text() and exists($x/*)) then (
      insert node <childtext>
        {$x/text()}
       </childtext> as first into $x
        (: here should be some code to delete the text only:)
    ) else ()
  )
)
return $i

Я не мог удалить текст с родственным узлом.


person Prakash Thapa    schedule 13.01.2014    source источник
comment
сначала я могу создать дочерний текст узла со значением text(). Теперь я должен удалить старый текст, который все еще там › Я не могу удалить этот только этот текст. если я хочу сделать значение пустым, другой дочерний узел также будет удален.   -  person Prakash Thapa    schedule 13.01.2014
comment
Вот что я пытался сделать: пусть $a := .... вернуть копию $i := $a изменить (для $x в $i/потомок-или-я::* вернуть (если($x/текст( ) и существует($x/*)) затем ( вставить узел ‹childtext› {$x/text()} ‹/childtext› первым в $x, (: здесь следует каким-то образом удалить этот текст или обновить его до следующего уровня: )) иначе ( ) )) вернуть $i   -  person Prakash Thapa    schedule 13.01.2014
comment
Пожалуйста, отредактируйте этот код в соответствии с вашим вопросом (здесь он плохо читается) и не опускайте части кода, чтобы он больше не работал (let $a := .... точно не рабочий код). Какие проблемы у вас есть с вашим текущим кодом?   -  person Jens Erat    schedule 13.01.2014
comment
Сделанный!! пожалуйста, проверьте вопрос еще раз   -  person Prakash Thapa    schedule 13.01.2014
comment
@dirkk: Если есть проблема с публикацией, подробно опишите проблему, а не просто публикуйте то, что вы пробовали. См. этот мета-пост о том, приемлемы ли комментарии о том, что вы пробовали, и есть ли альтернативы тому, что вы пробовали. Спасибо!   -  person Qantas 94 Heavy    schedule 25.01.2014
comment
@ Qantas94Heavy Честно говоря, я не знаю, что я должен был спросить вместо этого в этом случае. Код XQuery отсутствовал, и в результате моего комментария ОП предоставил эту информацию и, как вы можете видеть, ответил на вопрос. Так что на самом деле я думаю, что это было весьма полезно, и все остальное, что я мог бы спросить, было бы просто изменением речи, например. Пожалуйста, покажите нам какой-нибудь код или Вы уже пробовали что-то с XQuery. Итак, что было бы более полезной версией моего комментария в данном конкретном случае?   -  person dirkk    schedule 25.01.2014


Ответы (2)


Поскольку вы хотите заменить элемент, вы должны просто использовать конструкцию replace вместо того, чтобы вставлять новый элемент и удалять старый. Мне кажется намного проще:

copy $i := $a
modify (
  for $x in $i/descendant-or-self::*[exists(*)]/text()
  return replace node $x with <childtext>{$x}</childtext>
)
return $i
person dirkk    schedule 13.01.2014
comment
Да Да Да, именно этого я и хотел :-) Спасибо @dirkk :-) - person Prakash Thapa; 13.01.2014
comment
Привет, Диркк. Это работает только для одного текста(). это означает, что не будет работать что-то вроде ‹a›ab‹b /› ab‹/a›. Как это решить. - person Prakash Thapa; 13.01.2014
comment
@PrakashThapa Я отредактировал свой ответ, хотя видел ваше решение. Мой обновленный ответ в целом лучше, чем раньше (помещение условий непосредственно как предикат в оператор for), а также таким образом учитывает несколько элементов text(). Я бы очень предпочел это решение, поскольку оно легче читается, а также более производительно. - person dirkk; 13.01.2014

Модифицированное решение от @dirkk здесь:

copy $i := $a
modify (
  for $x in $i/descendant-or-self::*
  return (
    if($x/text() and exists($x/*)) then (
      if(count($x/text())=1) then (
      replace node $x/text() with <child>    {$x/text()}</child>
      ) else (
        for $j at $pos in 1 to count($x/text())
        return 
       replace node $x/text()[$pos] with <child>{$x/text()[$pos]}</child>

    )


    ) else ()
  )
)
return $i

Еще раз, спасибо.

person Prakash Thapa    schedule 13.01.2014