XQuery:根据在同一查询中进行的更新来更新节点

时间:2015-06-12 19:23:50

标签: xml xpath xquery

我喜欢使用一些查询来操作XML文件。我想在现有节点中添加一些属性,如果它们在执行查询之前或期间没有它。

例如:

   // if there is a price and the parents don't have 
   // the attribute named hasPrice then add it to them

   <products hasPrice='yes' >  
        <item hasPrice='yes'> 
            <price>100 </price> 
        </item>  
        <item hasPrice='yes'> 
            <price>100 </price> 
        </item>  
    </products>

我尝试了以下XQuery,但它说Duplicate attribute hasPrice

declare function local:propagatePrice($x)
{
  copy $t := $x 
  modify (
    for $y in $t//price,
    $z in $y/ancestor::*   
    return if ($z/@hasPrice) then () 
    else (insert node (attribute { 'hasPrice' } {'yes'}) into $z)
  )
  return $t
};

let $db := doc('products.xq')
let $temp := local:propagatePrice($db)
return $temp

3 个答案:

答案 0 :(得分:1)

我不太清楚你发现了什么困难。您尝试实现的目标当然可以使用XQuery(或者使用XSLT,这对于转换XML树更方便,特别是对于多个转换过程)。

在XQuery中,你可以在内存中操作一些XML树,所以如果你有&#34;转换&#34;逻辑在2个函数中,那么你可以&#34;链&#34;他们是这样的:

let $input  := <products> ... </products>
let $temp   := my:first-pass($input)
let $result := my:second-pass($temp)
return
   $result

或更简洁:

my:second-pass(
   my:first-pass(
      <products> ... </products>))

答案 1 :(得分:1)

您可以在price子句中检查hasPrice后代元素的存在和where属性的不存在:

declare function local:propagatePrice($x)
{
  copy $t := $x 
  modify (
    for $z in $t//*
    where not($z/@hasPrice) and $z//price
    return (insert node (attribute { 'hasPrice' } {'yes'}) into $z)
  )
  return $t
};

我在XQuery中看到的主要问题是,$y/ancestor::*可能会为不同的$y返回相同的元素,因为它们可以共享相同的祖先元素。除了没有效率之外,你得到的错误信息可能与这个事实有关; 可能 if ($z/@hasPrice)针对“缓存”&#39;进行评估值或某事,以便insert语句最终在同一祖先元素上执行多次。

答案 2 :(得分:1)

现在问题不同了。它是关于XQuery Update(它是XQuery的标准扩展,所以通常如果你没有提到它,我们不会假设你使用它。)

更新在XQuery Update中的运行方式与使用SQL之类的语言或任何具有“直接副作用”的语言不同。在XQuery Update中,除了计算XQuery表达式的返回值之外,评估查询还会做一些额外的事情。它还会计算“隐藏结果”,待定更新列表

每次评估更新指令(如insert node)时,相应的更改都会记录在日志之类的内容中。只有在评估完整个查询之后,才会立即播放所有更改。

开发人员的主要影响是,您无法在查询的其他部分看到更改。所有读取操作将始终看到评估开始时的世界。

这与SQL不同,但它非常适合功能语言。恕我直言,它也更符合数据库中ACID交易的概念。所以在某些情况下看起来可能会令人惊讶,但是当你知道它是如何工作的时候很容易:在你的测试条件下,它根本看不到在同一个查询中创建的新属性。