Выполнение xdmp:node-replace() для последовательности элементов и замена ее одним элементом

Итак, у меня есть интересная проблема, предположим, что у меня есть этот документ (example.xml) в базе данных MarkLogic:

<Enrolls>
  <Enroll>
    <Status> Active </Status>
    <boom> boom2 </boom>
  </Enroll>
    <Enroll>
    <Status> Active </Status>
    <boom> boom </boom>
  </Enroll>
  <Enroll>
    <Status> Inactive </Status>
    <boom> boom </boom>
  </Enroll>
</Enrolls>

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

<Enrolls>
  <boom> boom for the actives </boom>
  <Enroll>
    <Status> Inactive </Status>
    <boom> boom </boom>
  </Enroll>
</Enrolls>

Чтобы это сделать, вот код, который я написал:

xdmp:node-replace((doc("example.xml")/Enrolls/Enroll[Status eq " Active "]), <boom> boom for the actives </boom>)

Но вот результат, который я получаю:

<Enrolls>
  <boom> boom for the actives </boom>
  <boom> boom for the actives </boom>
  <Enroll>
    <Status> Inactive </Status>
    <boom> boom </boom>
  </Enroll>
</Enrolls>

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


person Andy Chan    schedule 05.03.2020    source источник


Ответы (1)


Рассмотрите возможность выполнения xdmp:node-delete для активных и отдельного xdmp:node-insert-child для родителя.

for $active in doc("example.xml")/Enrolls/Enroll[Status eq " Active "]
return 
  if ($active/following-sibling::Enroll[Status eq " Active "])
  then xdmp:node-delete($active)
  else xdmp:node-replace($active, <boom> boom for the actives </boom>)

Или сделайте xdmp:node-replace на первом и xdmp:node-delete на остальных. Вы должны иметь возможность сделать все это в одном запросе, так что это будет только один коммит.

let $enrolls := doc("example.xml")/Enrolls
return ( 
  $enrolls/Enroll[Status eq " Active "]/xdmp:node-delete(.),
  xdmp:node-insert-child($enrolls, <boom> boom for the actives </boom>)
)

Вы также можете перестроить родительский узел и полностью заменить его. Это может быть легче рассуждать, и, вероятно, будет похоже на производительность.

let $enrolls := doc("example.xml")/Enrolls
return 
  xdmp:node-replace($enrolls, 
    <Enrolls>
      <boom> boom for the actives </boom>
      {$enrolls/* except $enrolls/Enroll[Status eq " Active "]}
    </Enrolls>)
person grtjn    schedule 05.03.2020
comment
Но возможно ли вообще выполнить эту операцию в рамках одного xdmp:node-replace() или есть какая-то сверхчеловеческая функция копирования, удаления и вставки, существующая в XQuery, которая может сделать это за меня? Я хочу читать на диск только один раз, дважды читать с диска было бы больно. - person Andy Chan; 05.03.2020
comment
Вы можете создать функцию, которая использует любой из фрагментов кода в ответе, чтобы создать собственную функцию копирования, удаления и вставки супермена. Четвертый вариант — применить XSLT. - person Mads Hansen; 06.03.2020
comment
Как упоминалось выше и показано фрагментами кода от Mads, вы можете выполнять несколько операций с узлами в одном запросе, и они автоматически объединяются в один коммит. Нет необходимости выполнять операции узла в нескольких запросах. - person grtjn; 06.03.2020