XQuery比较两个文档并替换具有相同名称的节点

时间:2013-08-23 14:22:22

标签: xquery xquery-update

我的文档结构如下:

<INVT_DATA xmlns="http://www.mrbook.com/InventoryData">
    <AUTHOR>...</AUTHOR>
    <TITLE>...</TITLE>
    <PUBLISHER>...</PUBLISHER>
</INVT_DATA>

INVT_DATA的子节点始终是元素,而不是文本节点。 我想使用XQuery来比较具有相同结构的新文档。如果新元素和原始元素中存在子元素,则应替换它。如果新元素中存在子元素,但不是旧元素,则应将其附加到INVT_DATA。

我认为这个XQuery会起作用,但它总是似乎只是追加节点:

declare namespace invtdata="http://www.mrbook.com/InventoryData";

copy $oldInvtData := $oldXml

modify 
( 
  for $mpf in $newXml/invtdata:INVT_DATA/*
  let $oldMpf := $oldInvtData/invtdata:INVT_DATA/*[name()=name($mpf)] 
  return if(exists($oldMpf)) then 
  replace node $oldMpf with $mpf 
  else insert node $mpf into $oldInvtData 
)
return $oldInvtData 

我搜索了其他类似问题并找到了this,但这对我想做的事情来说有点过分。有什么建议?如果有帮助,我使用的是Oracle XML DB 11.2.0.3版本中的XmlQuery。

2 个答案:

答案 0 :(得分:1)

在name()上匹配容易出错,因为name()返回XML中出现的名称 - 如果你的两个输入将不同的前缀绑定到命名空间名称,则检查name()的相等性不会成功。如果将谓词更改为

[local-name() = local-name($mpf) 
 and
 namespace-uri() = namespace-uri($mpf)]

您的代码应该更好。


附录:

也就是说,给定一个XML文档Brad1.xml,其中包含以下内容:

<INVT_DATA xmlns="http://www.mrbook.com/InventoryData">
  <AUTHOR>old author</AUTHOR>
  <TITLE>old title</TITLE>
  <PUBLISHER>old publisher</PUBLISHER>
</INVT_DATA>

和包含以下内容的XML文档Brad2.xml:

<id:INVT_DATA xmlns:id="http://www.mrbook.com/InventoryData">
  <id:AUTHOR>new author</id:AUTHOR>
  <id:PUBLISHER>new publisher</id:PUBLISHER>
</id:INVT_DATA>

代码:

declare namespace invtdata="http://www.mrbook.com/InventoryData";

declare variable $oldXml := doc('.../Brad1.xml');
declare variable $newXml := doc('.../Brad2.xml');

copy $oldInvtData := $oldXml

modify 
( 
  for $mpf in $newXml/invtdata:INVT_DATA/*
  let $oldMpf := $oldInvtData/invtdata:INVT_DATA/*
                 [local-name() = local-name($mpf)
                  and namespace-uri() = namespace-uri($mpf)] 
  return if(exists($oldMpf)) then 
  replace node $oldMpf with $mpf 
  else insert node $mpf into $oldInvtData 
)
return $oldInvtData 

评估为:

<INVT_DATA xmlns="http://www.mrbook.com/InventoryData"
           xmlns:id="http://www.mrbook.com/InventoryData">
    <id:AUTHOR>new author</id:AUTHOR>
    <TITLE>old title</TITLE>
    <id:PUBLISHER>new publisher</id:PUBLISHER>
</INVT_DATA>

如果你没有看到任何节点被替换,一个可能的原因是XPath表达式中的一个错误(你确定它们都是正确的吗?没有拼写错误?);另一个是无法按预期绑定$ oldXml或$ newXml。

答案 1 :(得分:0)

这证明是正确的代码....只是一个小调整。

declare namespace invtdata="http://www.mrbook.com/InventoryData";

declare variable $oldXml := doc('.../Brad1.xml');
declare variable $newXml := doc('.../Brad2.xml');

copy $oldInvtData := $oldXml

modify 
( 
  for $mpf in $newXml/invtdata:INVT_DATA/*
  let $oldMpf := $oldInvtData/invtdata:INVT_DATA/*
                 [local-name() = local-name($mpf)
                  and namespace-uri() = namespace-uri($mpf)] 
  return if(exists($oldMpf)) then 
  replace node $oldMpf with $mpf 
  else insert node $mpf into $oldInvtData/invtdata:INVT_DATA 
)
return $oldInvtData 

感谢您的帮助!