2013-08-23 1 views
0

У меня есть документ, структурированный, как это:XQuery сравнить два документа и замену узлов с таким же именем

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

Subchildren из 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, но это совсем немного излишним для чего Я хочу делать. Какие-либо предложения? Если это помогает, я использую XmlQuery из Oracle XML DB версии 11.2.0.3.

+1

'name()' часто вызывает такие проблемы; он часто не возвращает префикс пространства имен, который вы ожидаете. Я бы попытался заменить его на 'localname()' и посмотреть, работает ли это. Если пространство имен имеет значение, вы всегда можете добавить другой предикат (или и), чтобы сравнить это. –

ответ

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 

Спасибо за помощь!

1

Соответствие по имени() подвержено ошибкам, потому что name() возвращает имя, как оно появляется в XML, - если ваши два входа связывают разные префиксы с именем пространства имен, проверка на равенство имени() won ' т. Если вы смените предикат на

[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, как вы намереваетесь.

+0

Спасибо за предложение! Я попробую! – Brad

+0

К сожалению, с локальным именем, даже без условия пространства имен-uri, он не заменяет никаких узлов вообще. Я попробовал '$ newXml // invtdata: INVT_DATA' только для того, чтобы убедиться, что я хватаю правый узел, но не добился успеха. – Brad

+0

Мы еще шаг. Когда я копирую и вставляю это, обновления происходят, но вставках нет. – Brad