I need to apply XSLT 1.0 transformation to following XML:
<ProfitLossFinancials>
<ProfitLossFinancial>
<Year>2013</Year>
<Turnover>13</Turnover>
<Profit>13</Profit>
</ProfitLossFinancial>
<ProfitLossFinancial>
<Year>2012</Year>
<Turnover>12</Turnover>
<Profit>12</Profit>
</ProfitLossFinancial>
</ProfitLossFinancials>
<BalanceSheetFinancials>
<BalanceSheetFinancial>
<Year>2013</Year>
<FixedAssets>13</FixedAssets>
</BalanceSheetFinancial>
<BalanceSheetFinancial>
<Year>2011</Year>
<FixedAssets>11</FixedAssets>
</BalanceSheetFinancial>
</BalanceSheetFinancials>
to have following output:
<Financials>
<Financial>
<Year>2013</Year>
<Turnover>13</Turnover>
<Profit>13</Profit>
<FixedAssets>13</FixedAssets>
</Financial>
<Financial>
<Year>2012</Year>
<Turnover>12</Turnover>
<Profit>12</Profit>
<FixedAssets/>
</Financial>
<Financial>
<Year>2011</Year>
<Turnover/>
<Profit/>
<FixedAssets>11</FixedAssets>
</Financial>
</Financials>
How to do that?
Please try this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="kFinancialByYear"
match="*[self::ProfitLossFinancial or self::BalanceSheetFinancial]"
use="Year" />
<xsl:variable name="af"
select="//*[self::ProfitLossFinancial or
self::BalanceSheetFinancial]"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<Financials>
<xsl:apply-templates select="$af[generate-id() =
generate-id(key('kFinancialByYear', Year)[1])]"
mode="group" />
</Financials>
</xsl:template>
<xsl:template match="*" mode="group">
<xsl:variable name="thisYearValues" select="key('kFinancialByYear', Year)" />
<Financial>
<xsl:apply-templates select="Year" />
<Turnover>
<xsl:value-of select="$thisYearValues/Turnover"/>
</Turnover>
<Profit>
<xsl:value-of select="$thisYearValues/Profit"/>
</Profit>
<FixedAssets>
<xsl:value-of select="$thisYearValues/FixedAssets"/>
</FixedAssets>
</Financial>
</xsl:template>
</xsl:stylesheet>
When run on this input:
<n>
<ProfitLossFinancials>
<ProfitLossFinancial>
<Year>2013</Year>
<Turnover>13</Turnover>
<Profit>13</Profit>
</ProfitLossFinancial>
<ProfitLossFinancial>
<Year>2012</Year>
<Turnover>12</Turnover>
<Profit>12</Profit>
</ProfitLossFinancial>
</ProfitLossFinancials>
<BalanceSheetFinancials>
<BalanceSheetFinancial>
<Year>2013</Year>
<FixedAssets>13</FixedAssets>
</BalanceSheetFinancial>
<BalanceSheetFinancial>
<Year>2011</Year>
<FixedAssets>11</FixedAssets>
</BalanceSheetFinancial>
</BalanceSheetFinancials>
</n>
The result is:
<Financials>
<Financial>
<Year>2013</Year>
<Turnover>13</Turnover>
<Profit>13</Profit>
<FixedAssets>13</FixedAssets>
</Financial>
<Financial>
<Year>2012</Year>
<Turnover>12</Turnover>
<Profit>12</Profit>
<FixedAssets></FixedAssets>
</Financial>
<Financial>
<Year>2011</Year>
<Turnover></Turnover>
<Profit></Profit>
<FixedAssets>11</FixedAssets>
</Financial>
</Financials>
Here are more straightforward solution using for-each and key:
<?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 match="Year" name="kyears" use="."/>
<xsl:template match="/*">
<Financials>
<xsl:for-each select="//Year[generate-id() =
generate-id(key('kyears', .)[1])]" >
<xsl:variable name="year" select="." />
<xsl:variable name="yearData" select="key('kyears', $year)/.." />
<Financial>
<xsl:copy-of select="$year"/>
<Turnover>
<xsl:value-of select="$yearData/Turnover"/>
</Turnover>
<Profit>
<xsl:value-of select="$yearData/Profit"/>
</Profit>
<FixedAssets>
<xsl:value-of select="$yearData/FixedAssets"/>
</FixedAssets>
</Financial>
</xsl:for-each>
</Financials>
</xsl:template>
</xsl:stylesheet>
Which generate the following output:
<?xml version="1.0"?>
<Financials>
<Financial>
<Year>2013</Year>
<Turnover>13</Turnover>
<Profit>13</Profit>
<FixedAssets>13</FixedAssets>
</Financial>
<Financial>
<Year>2012</Year>
<Turnover>12</Turnover>
<Profit>12</Profit>
<FixedAssets/>
</Financial>
<Financial>
<Year>2011</Year>
<Turnover/>
<Profit/>
<FixedAssets>11</FixedAssets>
</Financial>
</Financials>
<xsl:template match="ProfitLossFinancials">
<Financials>
<xsl:apply-templates select="ProfitLossFinancial"/>
</Financials>
</xsl:template>
<xsl:template match="ProfitLossFinancial">
<Financial>
<xsl:copy-of select="./*"/>
<xsl:copy-of select="../../BalanceSheetFinancials/BalanceSheetFinancial[Year = current()/Year]/FixedAssets"/>
</Financial>
</xsl:template>