XQuery node-name()函数,它是如何工作的?

时间:2015-05-11 13:32:13

标签: function xquery

我想为每个pair添加额外的对 我有这样的代码:

<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>

我需要在每对之后插入其他对,无论在哪个级别,前缀:“copy”具有不同的值:

<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()?它是如何工作的?我应该如何使用它?也许我应该使用另一种功能?

2 个答案:

答案 0 :(得分:1)

正如@ jens-erat所提到的,你不需要node-name(),相反你可能想要这样的东西:

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

更新 - 正如您在评论中提到的那样,只会复制最外面的对,如果您想复制所有对,无论它们的深度如何,那么您需要使用递归下降来转换输入。

我实际上发现在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)之外的所有内容element,在这种情况下,它为副本创建一个新的替代文本值。

copy-pair函数决定是否复制原始对,具体取决于我们是否已经复制,然后创建原始对的新副本,然后它本身执行递归下降。

答案 1 :(得分:-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
};