Skip to content

Instantly share code, notes, and snippets.

@tvnpraveen
Last active December 21, 2016 22:22
Show Gist options
  • Save tvnpraveen/b35fc2a2dee2a5875cdc0c96736930a2 to your computer and use it in GitHub Desktop.
Save tvnpraveen/b35fc2a2dee2a5875cdc0c96736930a2 to your computer and use it in GitHub Desktop.
XML Comparison Library
module namespace xmlCompare = "http://lib/utils/xmlCompare";
declare variable $xml1 := ();
declare variable $xml2 := ();
declare variable $idReference := ();
declare variable $resultMap := map:map();
declare function xmlCompare:getPosition($node as node()){
let $lastToken := fn:tokenize(xdmp:path($node),"[/]")[fn:last()]
return
if(fn:contains($lastToken,"[")) then
fn:tokenize(fn:tokenize($lastToken,"[\[]")[fn:last()],"[\]]")[1]
else()
};
declare function xmlCompare:getPath($node as node()){
fn:string-join(fn:tokenize(xdmp:path($node),"/")[3 to fn:last()],"/")
};
declare function xmlCompare:processNode($node1 as node(), $node2 as node())
{
if(fn:not(fn:deep-equal($node1, $node2))) then
typeswitch($node1)
case text()
return
(
if(fn:normalize-space($node1) ne fn:normalize-space($node2)) then
map:put($resultMap,xdmp:path($node1)||","||fn:normalize-space($node1)||","||fn:normalize-space($node2),"")
else()
)
case element()
return
(
for $childNode1 in $node1/node()
return
if($childNode1 instance of text()) then
let $childNode2 :=
xdmp:value("$node2/node()[fn:local-name(..) eq fn:local-name($childNode1/..)]")/fn:string()
return
if(fn:not(fn:exists($childNode2))) then
map:put($resultMap,xdmp:path($childNode1)||","||$childNode1||",","")
else(
if(fn:normalize-space($childNode1) ne fn:normalize-space($childNode2)) then
map:put($resultMap,xdmp:path($childNode1)||","||$childNode1||","||$childNode2,"")
else()
)
else(
let $localName := fn:local-name($childNode1)
let $id-elemName := $idReference/element-ref[element-name/text() eq $localName]/element-id/fn:string()
let $idNode :=
if ($id-elemName) then
$childNode1/node()[fn:local-name(.) eq $id-elemName]
else()
let $id := $idNode/fn:string()
let $childNode2 :=
if($id-elemName) then
(
xdmp:value("$node2/node()[node()/fn:local-name(.) eq $id-elemName][node()/fn:string() eq $id]")
)
else
(
let $childNode1Path := xmlCompare:getPath($childNode1)
return
xdmp:value("$xml2/"||$childNode1Path)
)
return(
if(fn:not(fn:exists($childNode2))) then
map:put($resultMap,xdmp:path($childNode1)||",Exists,Does Not Exist","")
else(
xmlCompare:processNode($childNode1,$childNode2)
)
)
)
)
default return ()
else()
};
declare function xmlCompare:compare($doc1, $doc2, $idRef) {
let $stripSpaceStyle :=
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:template match="@*|element( )">
<xsl:copy>
<xsl:apply-templates select="@*|element( )|text()[ string-length(normalize-space(string(.))) gt 0 ]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
let $_ := xdmp:set($xml1, xdmp:xslt-eval($stripSpaceStyle,$doc1/node())/element())
let $_ := xdmp:set($xml2, xdmp:xslt-eval($stripSpaceStyle,$doc2/node())/element())
let $_ := xdmp:set($idReference, $idRef/node())
let $_ := xmlCompare:processNode($xml1, $xml2)
return
map:keys($resultMap)
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment