我喜欢使用一些查询来操作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
答案 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交易的概念。所以在某些情况下看起来可能会令人惊讶,但是当你知道它是如何工作的时候很容易:在你的测试条件下,它根本看不到在同一个查询中创建的新属性。