Reputation: 215
I have one big xml file with different node sets that I need to combine using xsl based on a unique element value that both nodes contain.
Here's a sample of the xml file that needs to be transformed:
<root>
<node1>
<funds>
<fund>
<FundId>a</FundId>
<FundName>fund a</FundName>
<SomeInfo>some info</SomeInfo>
</fund>
<fund>
<FundId>b</FundId>
<FundName>fund b</FundName>
<SomeInfo>some info</SomeInfo>
</fund>
<fund>
<FundId>c</FundId>
<FundName>fund c</FundName>
<SomeInfo>some info</SomeInfo>
</fund>
</funds>
</node1>
<node2>
<funds>
<fund>
<FundId>a</FundId>
<MaxInvestmentAmount>200</MaxInvestmentAmount>
<MinInvestmentAmount>1</MinInvestmentAmount>
</fund>
<fund>
<FundId>b</FundId>
<MaxInvestmentAmount>100</MaxInvestmentAmount>
<MinInvestmentAmount>5</MinInvestmentAmount>
</fund>
<fund>
<FundId>c</FundId>
<MaxInvestmentAmount>50</MaxInvestmentAmount>
<MinInvestmentAmount>20</MinInvestmentAmount>
</fund>
</funds>
</node2>
</root>
And here's the desired output:
<node>
<funds>
<fund>
<FundId>a<FundId/>
<FundName>fund a</FundName>
<SomeInfo>some info</SomeInfo>
<MaxInvestmentAmount>200</MaxInvestmentAmount>
<MinInvestmentAmount>1</MinInvestmentAmount>
</fund>
<fund>
<FundId>b<FundId/>
<FundName>fund b</FundName>
<SomeInfo>some info</SomeInfo>
<MaxInvestmentAmount>100</MaxInvestmentAmount>
<MinInvestmentAmount>5</MinInvestmentAmount>
</fund>
<fund>
<FundId>c<FundId/>
<FundName>fund c</FundName>
<SomeInfo>some info</SomeInfo>
<MaxInvestmentAmount>50</MaxInvestmentAmount>
<MinInvestmentAmount>20</MinInvestmentAmount>
</fund>
</funds>
</node>
I've tried template matching but this doesn't seem to work the way I have tried it since both nodes have the same inner node names so they keep overriding each other.
Upvotes: 0
Views: 196
Reputation: 29022
A solid method to achieve this is by using an xsl:key
over the <fund>
elements with the FundId
as key. One relevant restriction of this approach is that only the FundId
keys of the first child element - here <node1>
- are merged. If other child elements contain more values, this method will not work as expected.
Here is the XSLT-1.0 stylesheet:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:key name="keyFund" match="fund" use="FundId" />
<xsl:template match="/root">
<node>
<funds>
<xsl:for-each select="*[1]/funds/fund">
<fund>
<xsl:copy-of select="FundId" />
<xsl:for-each select="key('keyFund',FundId)">
<xsl:copy-of select="current()/*[not(self::FundId)]" />
</xsl:for-each>
</fund>
</xsl:for-each>
</funds>
</node>
</xsl:template>
</xsl:stylesheet>
Its output is:
<?xml version="1.0"?>
<node>
<funds>
<fund>
<FundId>a</FundId>
<FundName>fund a</FundName>
<SomeInfo>some info</SomeInfo>
<MaxInvestmentAmount>200</MaxInvestmentAmount>
<MinInvestmentAmount>1</MinInvestmentAmount>
</fund>
<fund>
<FundId>b</FundId>
<FundName>fund b</FundName>
<SomeInfo>some info</SomeInfo>
<MaxInvestmentAmount>100</MaxInvestmentAmount>
<MinInvestmentAmount>5</MinInvestmentAmount>
</fund>
<fund>
<FundId>c</FundId>
<FundName>fund c</FundName>
<SomeInfo>some info</SomeInfo>
<MaxInvestmentAmount>50</MaxInvestmentAmount>
<MinInvestmentAmount>20</MinInvestmentAmount>
</fund>
</funds>
</node>
Upvotes: 1