2015-05-11 2 views
0

Я хочу добавить дополнительные пары для каждого pair.
У меня есть такой код:Функция XQuery node-name(), как она работает?

<data> 
<pair> 
    <key>keyName1</key> 
    <value>something1</value> 
</pair> 
<pair> 
    <key>keyName2</key> 
    <value>something2</value> 
</pair> 
<pair> 
    <key>keyName3</key> 
    <value> 
      <listOfPairs> 
       <pair> 
        <key>keyName4</key> 
        <value>Something6</value> 
       </pair> 
      </listOfPairs> 
    </value> 
</pair> 
<pair> 
    <key>keyName5</key> 
    <value>Something9</value> 
</pair> 
</data> 

и мне нужно вставить другие пары после каждой пары независимо от того, в каком уровне, с префиксом: «копировать» с другим значением:

<data> 
<pair> 
    <key>keyName1</key> 
    <value>something1</value> 
</pair> 
<pair> 
    <key>copy_keyName1</key> 
    <value>another1</value> 
</pair> 
<pair> 
    <key>keyName2</key> 
    <value>something2</value> 
</pair> 
<pair> 
    <key>copy_keyName2</key> 
    <value>another2</value> 
</pair> 
<pair> 
    <key>keyNamedwithLists</key> 
    <value> 
     <listOfPairs> 
      <pair> 
       <key>keyName4</key> 
       <value>Something6</value> 
      </pair> 
      <pair> 
       <key>copy_keyName4</key> 
       <value>Another6</value> 
      </pair> 
     </listOfPairs> 
    </value> 
</pair> 
<pair> 
    <key>keyName5</key> 
    <value>Something9</value> 
</pair> 
<pair> 
    <key>copy_keyName5</key> 
    <value>another9</value> 
</pair> 
</data> 

Для такого рода результат получить, мне нужно использовать функцию: node-name()? Как это работает? Как я должен его использовать? Возможно, мне нужно использовать другую функцию?

+1

'()' возвращает имя элемента. Для '/node-name()' он вернет 'foo'. Я не понимаю, зачем вам это нужно здесь, поскольку вам нужно только получить доступ к значениям, а не именам элементов. –

ответ

1

Как @ Jens-упомянуто и требовалось, вам не нужно node-name(), вместо того, чтобы по-видимому вы хотите что-то вроде этого:

<data> { 
for $pair in /data/pair 
return 
    ($pair, 
    <pair> 
     <key>{concat("copy_", $pair/key)}</key> 
     <value>some other value</value> 
    </pair>) 
}</data> 

UPDATE - Как вы упомянули в своем комментарии, что будет только скопировать внешний наиболее пар, если вы хотите скопировать все пары независимо от их глубины, тогда вам нужно использовать рекурсивный спуск для преобразования ввода.

Я на самом деле нашел, что писать это в XQuery для вашего конкретного случая использования довольно сложно, хотя решение довольно элегантное, я думаю :-) Мне было бы интересно, если кто-нибудь еще может подумать о лучшей реализации?

xquery version "1.0"; 

declare function local:copy-pair($pair as element(pair), $copying) as element(pair)+ { 
    (
     if(not($copying))then 
      $pair 
     else(), 
     <pair> 
      <key>{concat("copy_", $pair/key)}</key> 
       { local:recursive-descent($pair/key/following-sibling::node(), true()) } 
      </pair> 
    ) 
}; 

declare function local:recursive-descent($nodes, $copying) { 
    for $node in $nodes 
    return 
     (
     typeswitch($node) 
      case element(pair) return 
       local:copy-pair($node, $copying) 

      case element() return 
       element {node-name($node)} { 
        local:recursive-descent($node/node(), $copying) 
       } 

      case text() return 
       if($copying and $node/parent::value and empty($node/parent::value/element()))then 
        text { concat("SOME NEW VALUE. old value = ", $node) } 
       else 
        $node 

      default return 
       (
        $node, 
        local:recursive-descent($node/node(), false()) 
       ) 
     ) 
}; 

local:recursive-descent(/data, false()) 

recursive-descent функция в основном делает левый-направо рекурсивный спуск по дереву узлов. Любой элемент с именем pair переходит к функции copy-pair, иначе он просто копирует все, кроме того, когда у нас есть копия ($copying) текстового узла в элементе value, в этом случае он создает новое альтернативное текстовое значение для копии.

Функция copy-pair определяет, следует ли копировать исходную пару в зависимости от того, мы уже копируем или нет, а затем создаем новую копию исходной пары, затем она сама выполняет рекурсивный спуск.

+0

выглядит нормально, но когда я помещаю свою карту, я получаю эту пару в data/pair [key = "keyNamedwithLists"]/value/listOfPairs/pair, которая не получает никакой копии. Мне нужен этот конечный путь, который не имеет никакого отношения к любым парам. Каждая пара должна получить КОПИЮ. (Дополнение: данная карта динамична и изменяется каждый раз.) Согласно вашему ответу, он добавит дополнительные пары только к тем:/data/pair – tocaFuji

+0

@tocaFuji Помогло ли мое обновленное решение для вас? – adamretter

-1

Если у вас есть доступ к XQuery update и преобразование выражение, которое вы можете сделать что-то вроде: имя-узла

declare function local:additional-pairs($d){ 
copy $c:=$d 
modify(
    for $p in $c//pair[not(.//pair)] (: pairs with no descendant pairs :) 
    return insert node 
    <pair> 
     <key>copy_{$p/key/string()}</key> 
     <value>some new</value> 
    </pair> 
    after $p 
) 
    return $c 
}; 
+0

Вам также нужно учитывать детей пары, где значение представляет собой список пар, возможно, вам просто нужен предикат на $ c // pair – adamretter

+0

Спасибо Адаму, я сделал это изменение. В примере keyName3 не копируется (хотя имя ключа становится keyNamedwithLists?) В вашем коде это так. –