Reputation: 67
Struggling with an xslt transformation. Basically merging two different nodes based on a key (country code) so input xml has two parts.
If from part 1, country is found in part 2,
result = found
if from part 1, country is not found in part 2,
result = new
if from part 2, country is not found in part1,
result = not found
Input XML -
<Root>
<SomeData/>
<COUNTRIES>
<VALID_COUNTRY>
<COUNTRY>DK</COUNTRY>
<LANGUAGE>DANISH</LANGUAGE>
</VALID_COUNTRY>
<VALID_COUNTRY>
<COUNTRY>SE</COUNTRY>
<LANGUAGE>SWEDISH</LANGUAGE>
</VALID_COUNTRY>
<VALID_COUNTRY>
<COUNTRY>CA</COUNTRY>
<LANGUAGE>ENGLISH</LANGUAGE>
</VALID_COUNTRY>
<VALID_COUNTRY>
<COUNTRY>US</COUNTRY>
<LANGUAGE>ENGLISH</LANGUAGE>
</VALID_COUNTRY>
</COUNTRIES>
<SomeOtherData/>
<DATA>
<FURTHER>
<CountryInfo>
<Country>DK</Country>
</CountryInfo>
<CountryInfo>
<Country>US</Country>
</CountryInfo>
<CountryInfo>
<Country>UK</Country>
</CountryInfo>
<CountryInfo>
<Country>AU</Country>
</CountryInfo>
</FURTHER>
</DATA>
</Root>
Output XML
<Root>
<SomeData/>
<COUNTRIES>
<VALID_COUNTRY>
<COUNTRY>DK</COUNTRY>
<LANGUAGE>DANISH</LANGUAGE>
<FOUND>YES</FOUND>
</VALID_COUNTRY>
<VALID_COUNTRY>
<COUNTRY>SE</COUNTRY>
<LANGUAGE>SWEDISH</LANGUAGE>
<FOUND>NEW COUNTRY</FOUND>
</VALID_COUNTRY>
<VALID_COUNTRY>
<COUNTRY>CA</COUNTRY>
<LANGUAGE>ENGLISH</LANGUAGE>
<FOUND>NEW COUNTRY</FOUND>
</VALID_COUNTRY>
<VALID_COUNTRY>
<COUNTRY>US</COUNTRY>
<LANGUAGE>ENGLISH</LANGUAGE>
<FOUND>YES</FOUND>
</VALID_COUNTRY>
<VALID_COUNTRY>
<COUNTRY>UK</COUNTRY>
<FOUND>NOT FOUND</FOUND>
</VALID_COUNTRY>
<VALID_COUNTRY>
<COUNTRY>AU</COUNTRY>
<FOUND>NOT FOUND</FOUND>
</VALID_COUNTRY>
</COUNTRIES>
<SomeOtherData/>
<DATA>
<FURTHER>
<CountryInfo>
<Country>DK</Country>
</CountryInfo>
<CountryInfo>
<Country>US</Country>
</CountryInfo>
<CountryInfo>
<Country>UK</Country>
</CountryInfo>
<CountryInfo>
<Country>AU</Country>
</CountryInfo>
</FURTHER>
</DATA>
</Root>
have tried using xslt group-by (for 2.0) and key function along with generate id, but not getting the right output. I can use xslt 3.0 for this one.
Here is the code, I have tried,
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:hci="http://sap.com/it/" exclude-result-prefixes="hci">
<xsl:output method="xml" indent="yes"/>
<!-- Identity template : copy all text nodes, elements and attributes -->
<xsl:key name="CountryKey" match="//FURTHER/CountryInfo" use="Country"/>
<xsl:variable name="tempCountry" select="./COUNTRY"/>
<xsl:template match="/*">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="VALID_COUNTRY">
<xsl:for-each select="//VALID_COUNTRY[generate-id()=generate-id(key('CountryKey', ./COUNTRY)[1])]">
<VALID_COUNTRY> <xsl:value-of select="./COUNTRY"></xsl:value-of> </VALID_COUNTRY>
<LANGUAGE><xsl:value-of select="./LANGUAGE"></xsl:value-of></LANGUAGE>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Views: 361
Reputation: 167716
As you say you can use XSLT 2 or 3 you could use for-each-group
in any case or xsl:merge
with XSLT 3; grouping would be
<xsl:mode on-no-match="shallow-copy"/>
<xsl:mode name="add" on-no-match="shallow-copy"/>
<xsl:template match="COUNTRIES">
<xsl:copy>
<xsl:for-each-group select="VALID_COUNTRY, /Root/DATA/FURTHER/CountryInfo" group-by="COUNTRY, Country">
<xsl:apply-templates select="." mode="add"/>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="VALID_COUNTRY/LANGUAGE" mode="add">
<xsl:copy-of select="."/>
<FOUND>
<xsl:value-of select="if (current-group()[2]) then 'YES' else 'NEW COUNTRY'"/>
</FOUND>
</xsl:template>
<xsl:template match="CountryInfo" mode="add">
<VALID_COUNTRY>
<COUNTRY>
<xsl:value-of select="Country"/>
</COUNTRY>
<FOUND>NOT FOUND</FOUND>
</VALID_COUNTRY>
</xsl:template>
https://xsltfiddle.liberty-development.net/ejivJse
Upvotes: 2