Reputation: 137
I have an xml file as below propNode.xml
<NODES>
<NODE>
<NODELINE CLASS="Item" TYPE="Item" >
<ATTR_NODES>
<ATTR_NODE NAME="myName" />
<ATTR_NODE NAME="myDesc />
</ATTR_NODES>
</NODELINE>
<NODELINE CLASS="Item1" TYPE="Item1" >
<ATTR_NODES>
<ATTR_NODE NAME="myName1" />
<ATTR_NODE NAME="myDesc1" />
</ATTR_NODES>
</NODELINE>
<NODELINE CLASS="Item2" TYPE="Item2" >
<ATTR_NODES>
<ATTR_NODE NAME="myName2" />
<ATTR_NODE NAME="myDesc2" />
</ATTR_NODES>
</NODELINE>
</NODE>
</NODES>
I want to read this xml and using it, I need to merge the following two xml files source.xml
<NODES>
<NODE>
<NODELINE CLASS="Item" TYPE="Item" >
<ATTR_NODES>
<ATTR_NODE NAME="myName" VALUE="myNameValue" />
<ATTR_NODE NAME="myDesc" VALUE="test-myDescValue" />
<ATTR_NODE NAME="myId" VALUE="test-myIdValue" />
</ATTR_NODES>
</NODELINE>
<NODELINE CLASS="Item1" TYPE="Item1" >
<ATTR_NODES>
<ATTR_NODE NAME="myName1" VALUE="myNameValue1" />
<ATTR_NODE NAME="myDesc1" VALUE="myDescValue1"/>
<ATTR_NODE NAME="myId1" VALUE="myIdValue1" />
</ATTR_NODES>
</NODELINE>
<NODELINE CLASS="Item2" TYPE="Item2" >
<ATTR_NODES>
<ATTR_NODE NAME="myName2" VALUE="test-myNameValue2" />
<ATTR_NODE NAME="myDesc2" VALUE="myDescValue2"/>
<ATTR_NODE NAME="myId2" VALUE="test-myIdValue2" />
</ATTR_NODES>
</NODELINE>
</NODE>
</NODES>
And target.xml
<NODES>
<NODE>
<NODELINE CLASS="Item" TYPE="Item" >
<ATTR_NODES>
<ATTR_NODE NAME="myName" VALUE="myNameValue" />
<ATTR_NODE NAME="myDesc" VALUE="myDescValue" />
<ATTR_NODE NAME="myId" VALUE="myIdValue" />
</ATTR_NODES>
</NODELINE>
<NODELINE CLASS="Item1" TYPE="Item1" >
<ATTR_NODES>
<ATTR_NODE NAME="myName1" VALUE="myNameValue1" />
<ATTR_NODE NAME="myDesc1" VALUE="myDescValue1"/>
<ATTR_NODE NAME="myId1" VALUE="myIdValue1" />
</ATTR_NODES>
</NODELINE>
<NODELINE CLASS="Item2" TYPE="Item2" >
<ATTR_NODES>
<ATTR_NODE NAME="myName2" VALUE="myNameValue2" />
<ATTR_NODE NAME="myDesc2" VALUE="myDescValue2"/>
<ATTR_NODE NAME="myId2" VALUE="myIdValue2" />
</ATTR_NODES>
</NODELINE>
</NODE>
</NODES>
The condition is reading the propNode.xml, if the value of @NAME matches in the source.xml and target.xml, then the values of @VALUE in the source.xml and target.xml needs to be compared and an output xml should be created as below:
desiredOutput.xml
<NODES>
<NODE>
<NODELINE CLASS="Item" TYPE="Item" >
<ATTR_NODES>
<ATTR_NODE NAME="myName" SRCVALUE="myNameValue" TGTVALUE="myNameValue" ISDIFF="false" />
<ATTR_NODE NAME="myDesc" SRCVALUE="test-myDescValue" TGTVALUE="myDescValue" ISDIFF="true" />
</ATTR_NODES>
</NODELINE>
<NODELINE CLASS="Item1" TYPE="Item1" >
<ATTR_NODES>
<ATTR_NODE NAME="myName1" SRCVALUE="myNameValue1" TGTVALUE="myNameValue1" ISDIFF="false" />
<ATTR_NODE NAME="myDesc1" SRCVALUE="myDescValue1" TGTVALUE="myDescValue1" ISDIFF="false" />
</ATTR_NODES>
</NODELINE>
<NODELINE CLASS="Item2" TYPE="Item2" >
<ATTR_NODES>
<ATTR_NODE NAME="myName2" SRCVALUE="test-myNameValue2" TGTVALUE="myNameValue2" ISDIFF="true" /> />
<ATTR_NODE NAME="myDesc2" SRCVALUE="myDescValue2" TGTVALUE="myDescValue2" ISDIFF="false" />
</ATTR_NODES>
</NODELINE>
</NODE>
</NODES>
The desiredOutput.xml should contain both the values of @VALUE from the source and the target if the value of @NAME selected in the propNode.xml. If the values of @VALUE are different then @ISDIFF should have a value "true" or else "false".
Is this whole operation possible using xslt? Something like generating xsl using the propNode.xml and then applying it on the source.xml and the target.xml to generate the desired output? How would this xsl look like?
Upvotes: 2
Views: 159
Reputation: 107357
Assuming that only the nodes (ATTR_NODE
) present in propNode.xml
need to be tested, the following XSLT should do the job:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="some.uri" version="1.0">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ATTR_NODE">
<xsl:variable name="NodeLine" select="../../@CLASS" />
<xsl:variable name="AttrName" select="@NAME" />
<xsl:variable name="SrcValue" select="document('source.xml')//NODELINE[@CLASS=$NodeLine]//ATTR_NODE[@NAME=$AttrName]/@VALUE" />
<xsl:variable name="TgtValue" select="document('target.xml')//NODELINE[@CLASS=$NodeLine]//ATTR_NODE[@NAME=$AttrName]/@VALUE" />
<xsl:element name="ATTR_NODE">
<xsl:attribute name="NAME">
<xsl:value-of select="$AttrName"/>
</xsl:attribute>
<xsl:attribute name="SRCVALUE">
<xsl:value-of select="$SrcValue" />
</xsl:attribute>
<xsl:attribute name="TGTVALUE">
<xsl:value-of select="$TgtValue" />
</xsl:attribute>
<xsl:attribute name="ISDIFF">
<xsl:value-of select="$SrcValue!=$TgtValue" />
</xsl:attribute>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The identity template is used to traverse and copy propNode
, with special processing for each ATTR_NODE
checks VALUE
in source and target, and then evaluated for equality. I've assumed that NODE_LINE/@CLASS
is sufficient to establish the identity of the NODE_LINE
- if it isn't, then you'll need to add additional checking e.g. @TYPE
as well.
The xslt is run against propnode.xml
, and source.xml
and target.xml
must be present in the same folder.
Output
<?xml version="1.0" encoding="utf-8"?>
<NODES>
<NODE>
<NODELINE CLASS="Item" TYPE="Item">
<ATTR_NODES>
<ATTR_NODE NAME="myName" SRCVALUE="myNameValue" TGTVALUE="myNameValue" ISDIFF="false" />
<ATTR_NODE NAME="myDesc" SRCVALUE="test-myDescValue" TGTVALUE="myDescValue" ISDIFF="true" />"
</ATTR_NODES>
</NODELINE>
<NODELINE CLASS="Item1" TYPE="Item1">
<ATTR_NODES>
<ATTR_NODE NAME="myName1" SRCVALUE="myNameValue1" TGTVALUE="myNameValue1" ISDIFF="false" />
<ATTR_NODE NAME="myDesc1" SRCVALUE="myDescValue1" TGTVALUE="myDescValue1" ISDIFF="false" />
</ATTR_NODES>
</NODELINE>
<NODELINE CLASS="Item2" TYPE="Item2">
<ATTR_NODES>
<ATTR_NODE NAME="myName2" SRCVALUE="test-myNameValue2" TGTVALUE="myNameValue2" ISDIFF="true" />
<ATTR_NODE NAME="myDesc2" SRCVALUE="myDescValue2" TGTVALUE="myDescValue2" ISDIFF="false" />
</ATTR_NODES>
</NODELINE>
</NODE>
</NODES>
Upvotes: 1