Remove duplicates but only on parent level XSLT 1.0 - xslt

I tried to find a solution to my problem, there are many solutions for deleting "plain" duplicates, but I couldn't find one. My problem is that I should somehow delete the duplicates, but unfortunately the parent node has the same name as the child node, so when I search for duplicates and delete them, it also deletes the child nodes, which should be. How can I delete only the parent nodes and leave the child nodes?
My XML:
<?xml version="1.0" encoding="UTF-8"?>
<invoices>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1878.95"/>
</amounts>
<allinvoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1878.95"/>
</amounts>
</invoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="0.00"/>
</amounts>
</invoice>
</allinvoice>
</invoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="0.00"/>
</amounts>
<allinvoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1878.95"/>
</amounts>
</invoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="0.00"/>
</amounts>
</invoice>
</allinvoice>
</invoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1900.00"/>
</amounts>
<allinvoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1900.00"/>
</amounts>
</invoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="0.00"/>
</amounts>
</invoice>
</allinvoice>
</invoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="0.00"/>
</amounts>
<allinvoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1900.00"/>
</amounts>
</invoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="0.00"/>
</amounts>
</invoice>
</allinvoice>
</invoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1900.00"/>
</amounts>
<allinvoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1900.00"/>
</amounts>
</invoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_2"/>
</cost>
<amounts>
<amount localamount="2700.00"/>
</amounts>
</invoice>
</allinvoice>
</invoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_2"/>
</cost>
<amounts>
<amount localamount="2700.00"/>
</amounts>
<allinvoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1900.00"/>
</amounts>
</invoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_2"/>
</cost>
<amounts>
<amount localamount="2700.00"/>
</amounts>
</invoice>
</allinvoice>
</invoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_3"/>
</cost>
<amounts>
<amount localamount="500.00"/>
</amounts>
<allinvoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_3"/>
</cost>
<amounts>
<amount localamount="500.00"/>
</amounts>
</invoice>
</allinvoice>
</invoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="0.00"/>
</amounts>
</invoice>
<allinvoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="0.00"/>
</amounts>
</invoice>
</allinvoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_2"/>
</cost>
<amounts>
<amount localamount="100.00"/>
</amounts>
<allinvoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_2"/>
</cost>
<amounts>
<amount localamount="100.00"/>
</amounts>
</invoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_3"/>
</cost>
<amounts>
<amount localamount="5000.00"/>
</amounts>
</invoice>
</allinvoice>
</invoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_3"/>
</cost>
<amounts>
<amount localamount="5000.00"/>
</amounts>
<allinvoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_2"/>
</cost>
<amounts>
<amount localamount="100.00"/>
</amounts>
</invoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_3"/>
</cost>
<amounts>
<amount localamount="5000.00"/>
</amounts>
</invoice>
</allinvoice>
</invoice>
</invoices>
My XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="more_than_one" match="invoice" use="concat(#buyer,
'|', invoicenumbers/invoicenumber/#name)"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="invoice[not(generate-id() = generate-id(key('more_than_one', concat(#buyer,
'|', invoicenumbers/invoicenumber/#name))[1]))]"/>
</xsl:stylesheet>
My Result:
<?xml version="1.0" encoding="UTF-8"?>
<invoices>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="1234"> </invoicenumber>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"> </COSTGROUP>
</cost>
<amounts>
<amount localamount="1878.95"> </amount>
</amounts>
<allinvoice> </allinvoice>
</invoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="5678"> </invoicenumber>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"> </COSTGROUP>
</cost>
<amounts>
<amount localamount="1900.00"> </amount>
</amounts>
<allinvoice> </allinvoice>
</invoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="1234"> </invoicenumber>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"> </COSTGROUP>
</cost>
<amounts>
<amount localamount="1900.00"> </amount>
</amounts>
<allinvoice> </allinvoice>
</invoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="5678"> </invoicenumber>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_3"> </COSTGROUP>
</cost>
<amounts>
<amount localamount="500.00"> </amount>
</amounts>
<allinvoice> </allinvoice>
</invoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="1234"> </invoicenumber>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"> </COSTGROUP>
</cost>
<amounts>
<amount localamount="0.00"> </amount>
</amounts>
</invoice>
<allinvoice> </allinvoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="5678"> </invoicenumber>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_2"> </COSTGROUP>
</cost>
<amounts>
<amount localamount="100.00"> </amount>
</amounts>
<allinvoice> </allinvoice>
</invoice>
</invoices>
What I want:
<?xml version="1.0" encoding="UTF-8"?>
<invoices>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1878.95"/>
</amounts>
<allinvoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1878.95"/>
</amounts>
</invoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="0.00"/>
</amounts>
</invoice>
</allinvoice>
</invoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1900.00"/>
</amounts>
<allinvoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1900.00"/>
</amounts>
</invoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="0.00"/>
</amounts>
</invoice>
</allinvoice>
</invoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1900.00"/>
</amounts>
<allinvoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1900.00"/>
</amounts>
</invoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_2"/>
</cost>
<amounts>
<amount localamount="2700.00"/>
</amounts>
</invoice>
</allinvoice>
</invoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_3"/>
</cost>
<amounts>
<amount localamount="500.00"/>
</amounts>
<allinvoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_3"/>
</cost>
<amounts>
<amount localamount="500.00"/>
</amounts>
</invoice>
</allinvoice>
</invoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="0.00"/>
</amounts>
</invoice>
<allinvoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="0.00"/>
</amounts>
</invoice>
</allinvoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_2"/>
</cost>
<amounts>
<amount localamount="100.00"/>
</amounts>
<allinvoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_2"/>
</cost>
<amounts>
<amount localamount="100.00"/>
</amounts>
</invoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_3"/>
</cost>
<amounts>
<amount localamount="5000.00"/>
</amounts>
</invoice>
</allinvoice>
</invoice>
</invoices>
Thank you for your help.
Regards.

The sample data is too long to check but your description sounds as if you want to improve your match patterns to e.g.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="more_than_one" match="/invoices/invoice" use="concat(#buyer,
'|', invoicenumbers/invoicenumber/#name)"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/invoices/invoice[not(generate-id() = generate-id(key('more_than_one', concat(#buyer,
'|', invoicenumbers/invoicenumber/#name))[1]))]"/>
</xsl:stylesheet>

Related

Duplicate in key (Muenchian Grouping)

it may sound strange, but is it the case that, for example, if we group it based on 3 things and also want to see a recurrence of a certain element in the key? Can anyone give a simple example if this exists? Although I searched for previous solutions, I only found one where duplicates were deleted.
I finally have my example.
My XML:
<?xml version="1.0" encoding="UTF-8"?>
<invoices>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1878.95"/>
</amounts>
</invoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="0.00"/>
</amounts>
</invoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1900.00"/>
</amounts>
</invoice>
<invoice buyer="Company_1">
<invoicenumbers>
<invoicenumber name="5678"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="0.00"/>
</amounts>
</invoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="1900.00"/>
</amounts>
</invoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_2"/>
</cost>
<amounts>
<amount localamount="2700.00"/>
</amounts>
</invoice>
<invoice buyer="Company_2">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_3"/>
</cost>
<amounts>
<amount localamount="500.00"/>
</amounts>
</invoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_1"/>
</cost>
<amounts>
<amount localamount="0.00"/>
</amounts>
</invoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_2"/>
</cost>
<amounts>
<amount localamount="100.00"/>
</amounts>
</invoice>
<invoice buyer="Company_3">
<invoicenumbers>
<invoicenumber name="1234"/>
</invoicenumbers>
<cost>
<COSTGROUP name="Group_3"/>
</cost>
<amounts>
<amount localamount="5000.00"/>
</amounts>
</invoice>
</invoices>
My XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:key name="Muenchian_Grouping"
match="/invoices/invoice"
use="concat(#buyer, '|', invoicenumbers/invoicenumber/#name)"/>
<xsl:key name="Muenchian_Grouping_by_costgroup"
match="/invoices/invoice"
use="concat(#buyer, '|', invoicenumbers/invoicenumber/#name, '|', cost/COSTGROUP/#name)"/>
<xsl:template match="/">
<Workbook>
<Worksheet ss:Name="Report">
<xsl:call-template name="ws_table"/>
</Worksheet>
</Workbook>
</xsl:template>
<xsl:template name="ws_table">
<Table>
<xsl:call-template name="columns"/>
<xsl:call-template name="columnHeader"/>
<xsl:apply-templates select="invoices/invoice[generate-id() = generate-id(key('Muenchian_Grouping',
concat(#buyer, '|', invoicenumbers/invoicenumber/#name))[1])]" mode="invoices"/>
</Table>
</xsl:template>
<xsl:template name="columns">
<Column ss:Width="269.25"/>
<Column ss:Width="218.25"/>
<Column ss:Width="291.75"/>
<Column ss:Width="276.75"/>
<Column ss:Width="276.75"/>
</xsl:template>
<xsl:template name="columnHeader">
<Row>
<!-- buyer -->
<Cell>
<Data ss:Type="String">buyer</Data>
</Cell>
<!-- invoicenumber -->
<Cell>
<Data ss:Type="String">invoicenumber</Data>
</Cell>
<!-- Group1_localamount -->
<Cell>
<Data ss:Type="String">Group1_localamount</Data>
</Cell>
<!-- Group1_localamount -->
<Cell>
<Data ss:Type="String">Group2_localamount</Data>
</Cell>
<!-- Group1_localamount -->
<Cell>
<Data ss:Type="String">Group3_localamount</Data>
</Cell>
</Row>
</xsl:template>
<xsl:template match="invoice" mode="invoices">
<xsl:variable name="Group1_data" select="key('Muenchian_Grouping_by_costgroup',
concat(#buyer, '|', invoicenumbers/invoicenumber/#name, '|', 'Group_1'))"/>
<xsl:variable name="Group2_data" select="key('Muenchian_Grouping_by_costgroup',
concat(#buyer, '|', invoicenumbers/invoicenumber/#name, '|', 'Group_2'))"/>
<xsl:variable name="Group3_data" select="key('Muenchian_Grouping_by_costgroup',
concat(#buyer, '|', invoicenumbers/invoicenumber/#name, '|', 'Group_3'))"/>
<Row>
<!-- buyer - when group1 is not exists -->
<Cell>
<Data ss:Type="String">
<xsl:value-of select="$Group1_data/#buyer | $Group2_data/#buyer | $Group3_data/#buyer"/>
</Data>
</Cell>
<!-- invoicenumber - when group1 is not exists -->
<Cell>
<Data ss:Type="String">
<xsl:value-of select="$Group1_data/invoicenumbers/invoicenumber/#name | $Group2_data/invoicenumbers/invoicenumber/#name | $Group3_data/invoicenumbers/invoicenumber/#name"/>
</Data>
</Cell>
<!-- Group1_localamount -->
<Cell>
<Data ss:Type="String">
<xsl:value-of select="$Group1_data/amounts/amount/#localamount"/>
</Data>
</Cell>
<!-- Group1_localamount -->
<Cell>
<Data ss:Type="String">
<xsl:value-of select="$Group2_data/amounts/amount/#localamount"/>
</Data>
</Cell>
<!-- Group1_localamount -->
<Cell>
<Data ss:Type="String">
<xsl:value-of select="$Group3_data/amounts/amount/#localamount"/>
</Data>
</Cell>
</Row>
</xsl:template>
</xsl:stylesheet>
So as you can see in the XML the "Company_1" has a duplicate value at "invoicenumber name="1234"" and at "invoicenumber name="5678"", and the question is how can i see both in the output excel file?
EDIT:
Expected result:
enter image description here

Need to merge 2 xml in xslt based on a common key

I have 2 source variables which need to be merged based on a common key in XSLT
Variable 1:I have added few properties for each employee.
<EmpDetails>
<Emp>
<ID>1</ID>
<Name>A</Name>
<Address>abc 123</Address>
<Contact>1234567890</Contact>
<DOB>01/01/1989</DOB>
<Emp>
<Emp>
<ID>2</ID>
<Name>B</Name>
<Address>ASDF</Address>
<Contact>123456</Contact>
<DOB>02/02/1990</DOB>
<Emp>
</EmpDetails>
Variable 2:
<EmpAgeDetails>
<EmpAge>
<ID>1</ID>
<Age>27</Age>
<EmpAge>
<EmpAge>
<ID>2</ID>
<Age>26</Age>
<EmpAge>
</EmpAgeDetails>
Expected output:
<EmpDetails>
<Emp>
<ID>1</ID>
<Name>A</Name>
<Address>abc 123</Address>
<Contact>1234567890</Contact>
<DOB>01/01/1989</DOB>
<Age>27</Age>
<Emp>
<Emp>
<ID>2</ID>
<Name>B</Name>
<Address>ASDF</Address>
<Contact>123456</Contact>
<DOB>02/02/1990</DOB>
<Age>26</Age>
<Emp>
</EmpDetails>
I am using a template to copy all elements from Variable 1 which is working fine.
But now I need to merge that extra element of Age.
Any help is appreciated
Using XSLT 3.0 and xsl:merge, as supported in the latest Altova XMLSpy/Raptor or Saxon 9.7 EE, you can use
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:math="http://www.w3.org/2005/xpath-functions/math" xmlns:array="http://www.w3.org/2005/xpath-functions/array" xmlns:map="http://www.w3.org/2005/xpath-functions/map" exclude-result-prefixes="array fn map math xs">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="doc1">
<EmpDetails>
<Emp>
<ID>1</ID>
<Name>A</Name>
<Address>abc 123</Address>
<Contact>1234567890</Contact>
<DOB>01/01/1989</DOB>
</Emp>
<Emp>
<ID>2</ID>
<Name>B</Name>
<Address>ASDF</Address>
<Contact>123456</Contact>
<DOB>02/02/1990</DOB>
</Emp>
</EmpDetails>
</xsl:param>
<xsl:param name="doc2">
<EmpAgeDetails>
<EmpAge>
<ID>1</ID>
<Age>27</Age>
</EmpAge>
<EmpAge>
<ID>2</ID>
<Age>26</Age>
</EmpAge>
</EmpAgeDetails>
</xsl:param>
<xsl:template match="/" name="xsl:initial-template">
<EmpDetails>
<xsl:merge>
<xsl:merge-source select="$doc1/EmpDetails/Emp">
<xsl:merge-key select="ID"></xsl:merge-key>
</xsl:merge-source>
<xsl:merge-source select="$doc2/EmpAgeDetails/EmpAge">
<xsl:merge-key select="ID"></xsl:merge-key>
</xsl:merge-source>
<xsl:merge-action>
<xsl:copy>
<xsl:apply-templates select="current-merge-group()[1]/*, fn:current-merge-group()[2]/Age"/>
</xsl:copy>
</xsl:merge-action>
</xsl:merge>
</EmpDetails>
</xsl:template>
</xsl:stylesheet>
Using XSLT 2.0 you could group:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:param name="doc1">
<EmpDetails>
<Emp>
<ID>1</ID>
<Name>A</Name>
<Address>abc 123</Address>
<Contact>1234567890</Contact>
<DOB>01/01/1989</DOB>
</Emp>
<Emp>
<ID>2</ID>
<Name>B</Name>
<Address>ASDF</Address>
<Contact>123456</Contact>
<DOB>02/02/1990</DOB>
</Emp>
</EmpDetails>
</xsl:param>
<xsl:param name="doc2">
<EmpAgeDetails>
<EmpAge>
<ID>1</ID>
<Age>27</Age>
</EmpAge>
<EmpAge>
<ID>2</ID>
<Age>26</Age>
</EmpAge>
</EmpAgeDetails>
</xsl:param>
<xsl:template match="/" name="main">
<EmpDetails>
<xsl:for-each-group select="$doc1/EmpDetails/Emp, $doc2/EmpAgeDetails/EmpAge" group-by="ID">
<xsl:copy>
<xsl:copy-of select="current-group()[1]/*, current-group()[2]/Age"/>
</xsl:copy>
</xsl:for-each-group>
</EmpDetails>
</xsl:template>
</xsl:stylesheet>

Navigating to the Nested child Attribute and Merge with the another Element

Here i am stuck with the XSLT transformation as i am very new and started learning.
Input XML
<SHOW_LIST>
<SHOW ID="12345">
<SHOW_INFO>xxx</SHOW_INFO>
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="1">
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="12345678"></SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
</SHOW_ELEMENT>
<SHOW_ELEMENT ID="2">
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="12345666"></SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
</SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
<SECONDARY_ELEMENT_LIST/>
<ALTERNATIVE_SHOW_LIST>
<SHOW ID="54321">
<SHOW_INFO>xxxa</SHOW_INFO>
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="3"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="4"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="5"> </SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
<SECONDARY_ELEMENT_LIST/>
</SHOW>
<SHOW ID="54322">
<SHOW_INFO>xxxb</SHOW_INFO>
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="6"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="7"> </SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
<SECONDARY_ELEMENT_LIST/>
</SHOW>
</ALTERNATIVE_SHOW_LIST>
</SHOW>
OUTPUT XML :
<SHOW_LIST>
<SHOW ID="12345">
<SHOW_INFO>xxx</SHOW_INFO>
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="1"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="2"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="3"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="4"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="5"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="6"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="7"> </SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
<SECONDARY_ELEMENT_LIST/>
<ALTERNATIVE_SHOW_LIST>
<SHOW ID="54321">
<SHOW_INFO>xxxa</SHOW_INFO>
<SECONDARY_ELEMENT_LIST/>
</SHOW>
<SHOW ID="54322">
<SHOW_INFO>xxxb</SHOW_INFO>
<SECONDARY_ELEMENT_LIST/>
</SHOW>
</ALTERNATIVE_SHOW_LIST>
</SHOW>
</SHOW_LIST>
I am able to navigate till Alternative_show_list and couldnt copy the SHOW_ELEMENTS and merge with the main SHOW_ELEMENT_LIST.
Anyone kindly help me in performing this
Another output of the same input file
<SHOW_LIST>
<SHOW ID="12345">
<SHOW_INFO>xxx</SHOW_INFO>
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="1"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="2"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="3"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="4"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="5"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="6"> </SHOW_ELEMENT>
<SHOW_ELEMENT ID="7"> </SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
<SECONDARY_ELEMENT_LIST/>
</SHOW>
</SHOW_LIST>
Now i am trying for this kind of output.
New Output XML
<?xml version="1.0" encoding="UTF-8"?>
<SHOW_LIST>
<SHOW ID="12345">
<SHOW_INFO>xxx</SHOW_INFO>
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="1">
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="12345678"></SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
</SHOW_ELEMENT>
<SHOW_ELEMENT ID="2">
<SHOW_ELEMENT_LIST>
<SHOW_ELEMENT ID="12345666"></SHOW_ELEMENT>
</SHOW_ELEMENT_LIST>
</SHOW_ELEMENT>
<SHOW_ELEMENT ID="3"/>
<SHOW_ELEMENT ID="4"/>
<SHOW_ELEMENT ID="5"/>
<SHOW_ELEMENT ID="6"/>
<SHOW_ELEMENT ID="7"/>
</SHOW_ELEMENT_LIST>
<SECONDARY_ELEMENT_LIST/>
</SHOW>
</SHOW_LIST>
This simple stylesheet will do the trick:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<!-- identity template -->
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- get all the SHOW_ELEMENT nodes -->
<xsl:template match="SHOW//SHOW_ELEMENT_LIST[not(ancestor::ALTERNATIVE_SHOW_LIST)]">
<SHOW_ELEMENT_LIST>
<xsl:copy-of select="..//SHOW_ELEMENT"/>
</SHOW_ELEMENT_LIST>
</xsl:template>
<!-- delete all SHOW_ELEMENT_LIST under ALTERNATIVE_SHOW_LIST -->
<xsl:template match="SHOW//SHOW_ELEMENT_LIST[ancestor::ALTERNATIVE_SHOW_LIST]"/>
</xsl:stylesheet>
<xsl:template match="ALTERNATIVE_SCHEDULE_LIST"/>
This helps for the second output XML to delete the ATERNATIVE_SCHEDULE_LIST element.
Please correct me if there is any other solution

XSLT transform to multiple complex types within for loop

I have a requirment to transform a XML with the below structure
<CustomerStatements>
<CustomerStatement>
<Name>ABC</Name>
<ID>1</ID>
<Amt>10</Amt>
</CustomerStatement>
<CustomerStatement>
<Name>ABC</Name>
<ID>1</ID>
<Amt>20</Amt>
</CustomerStatement>
<CustomerStatement>
<Name>XYZ</Name>
<ID>2</ID>
<Amt>30</Amt>
</CustomerStatement>
<CustomerStatement>
<Name>XYZ</Name>
<ID>2</ID>
<Amt>40</Amt>
</CustomerStatement>
</CustomerStatements>
To
<Customers>
<Customer>
<Name>ABC</Name>
<Id>1</Id>
<Amounts>
<Amount>10</Amount>
<Amount>20</Amount>
</Amounts>
</Customer>
<Customer>
<Name>XYZ</Name>
<Id>2</Id>
<Amount>30</Amount>
<Amount>40</Amount>
</Customer>
</Customers>
I tried using a for loop and taking the name into a variable to compare the name in the next record, but this doesn't work. Can you any one help me with a sample XSLT psudo code.
Thanks
I. When this XSLT 1.0 solution:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key
name="kCustByNameId"
match="CustomerStatement"
use="concat(Name, '+', ID)" />
<xsl:template match="/*">
<Customers>
<xsl:apply-templates
select="CustomerStatement[
generate-id() =
generate-id(key('kCustByNameId', concat(Name, '+', ID))[1])]" />
</Customers>
</xsl:template>
<xsl:template match="CustomerStatement">
<Customer>
<xsl:copy-of select="Name|ID" />
<Amounts>
<xsl:for-each select="key('kCustByNameId', concat(Name, '+', ID))/Amt">
<Amount>
<xsl:apply-templates />
</Amount>
</xsl:for-each>
</Amounts>
</Customer>
</xsl:template>
</xsl:stylesheet>
...is applied to the OP's original XML:
<CustomerStatements>
<CustomerStatement>
<Name>ABC</Name>
<ID>1</ID>
<Amt>10</Amt>
</CustomerStatement>
<CustomerStatement>
<Name>ABC</Name>
<ID>1</ID>
<Amt>20</Amt>
</CustomerStatement>
<CustomerStatement>
<Name>XYZ</Name>
<ID>2</ID>
<Amt>30</Amt>
</CustomerStatement>
<CustomerStatement>
<Name>XYZ</Name>
<ID>2</ID>
<Amt>40</Amt>
</CustomerStatement>
</CustomerStatements>
...the wanted result is produced:
<?xml version="1.0" encoding="UTF-8"?><Customers>
<Customer>
<Name>ABC</Name>
<ID>1</ID>
<Amounts>
<Amount>10</Amount>
<Amount>20</Amount>
</Amounts>
</Customer>
<Customer>
<Name>XYZ</Name>
<ID>2</ID>
<Amounts>
<Amount>30</Amount>
<Amount>40</Amount>
</Amounts>
</Customer>
</Customers>
The primary thing to look at here is Muenchian Grouping, which is the generally accepted method for grouping problems in XSLT 1.0.
II. Here's a more compact XSLT 2.0 solution:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<Customers>
<xsl:for-each-group select="CustomerStatement" group-by="ID">
<Customer>
<xsl:copy-of select="current-group()[1]/Name|current-group()[1]/ID" />
<Amounts>
<xsl:for-each select="current-group()/Amt">
<Amount>
<xsl:apply-templates />
</Amount>
</xsl:for-each>
</Amounts>
</Customer>
</xsl:for-each-group>
</Customers>
</xsl:template>
</xsl:stylesheet>
In this case, notice XSLT 2.0's use of the for-each-group element, which eliminates the need for the sometimes-verbose and potentially confusing Muenchian Grouping method.

Select distinct in XSLT relative to each elements

I try to retrieve a list of the attribute values of the children of an element but I want that the values only appears once.
For instance, I have the following XML
<root>
<sec>
<nom-title>
<nom-chapter>
<nom-article><data att="1.1"/></nom-article>
<nom-article>
<nom-item><data att="1.1"/></nom-item>
<nom-item><data att="1.2"/></nom-item>
</nom-article>
</nom-chapter>
<nom-chapter>
<nom-article><data att="2.1"/></nom-article>
<nom-article><data att="1.1"/></nom-article>
</nom-chapter>
</nom-title>
<nom-title>
<nom-chapter>
<nom-article><data att="1.1"/></nom-article>
</nom-chapter>
</nom-title>
</sec>
</root>
And I want a result like that:
<root>
<nom-title>
<att>1.1</att>
<att>1.2</att>
<att>2.1</att>
<nom-chapter>
<att>1.1</att>
<att>1.2</att>
<nom-article>
<att>1.1</att>
</nom-article>
<nom-article>
<att>1.1</att>
<att>1.2</att>
<nom-item><att>1.1</att></nom-item>
<nom-item><att>1.2</att></nom-item>
</nom-article>
</nom-chapter>
</nom-title>
<nom-title>
<att>1.1</att>
<nom-chapter>
<att>1.1</att>
<nom-article>
<att>1.1</att>
</nom-article>
</nom-chapter>
</nom-title>
</root>
I've tried to use the xsl:key element but it only returns the value for one element. In the example, it only returns 1.1 for the first title but not the second. The xsl I've used:
<xsl:key name="allAtt"
match="//*[starts-with(name(.),'nom-')]/data"
use="#att"/>
<xsl:template match="nom-title|nom-chapter|nom-article|nom-item">
<xsl:element name="name(.)">
<xsl:apply-templates select=".//*[starts-with(name(.),'nom-')]/data
</xsl:element>
</xsl:template>
<xsl:template match="data">
<xsl:variable name="att" select="#att"/>
<xsl:if test="generate-id(.)=generate-id(key('allAtt',$att)[1]">
<xsl:element name="att"><xsl:value-of select="$att"></xsl:element>
</xsl:if>
</xsl:template>
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kData-nom-article" match="data" use=
"concat(generate-id(ancestor::nom-article[1]),
'+', #att)"/>
<xsl:key name="kData-nom-chapter" match="data" use=
"concat(generate-id(ancestor::nom-chapter[1]),
'+', #att)"/>
<xsl:key name="kData-nom-title" match="data" use=
"concat(generate-id(ancestor::nom-title[1]),
'+', #att)"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="sec"><xsl:apply-templates/></xsl:template>
<xsl:template match="nom-title|nom-article|nom-chapter">
<xsl:copy>
<xsl:apply-templates mode="list" select=
".//data[generate-id()
=
generate-id(key(concat('kData-', name(current())),
concat(generate-id(current()),
'+', #att
)
)
[1]
)
]"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="data" mode="list">
<att><xsl:value-of select="#att"/></att>
</xsl:template>
<xsl:template match="non-item/data">
<att><xsl:value-of select="#att"/></att>
</xsl:template>
<xsl:template match="*[not(self::nom-item)]/data"/>
</xsl:stylesheet>
when applied on the provided XML document:
<root>
<sec>
<nom-title>
<nom-chapter>
<nom-article>
<data att="1.1"/>
</nom-article>
<nom-article>
<nom-item>
<data att="1.1"/>
</nom-item>
<nom-item>
<data att="1.2"/>
</nom-item>
</nom-article>
</nom-chapter>
<nom-chapter>
<nom-article>
<data att="2.1"/>
</nom-article>
<nom-article>
<data att="1.1"/>
</nom-article>
</nom-chapter>
</nom-title>
<nom-title>
<nom-chapter>
<nom-article>
<data att="1.1"/>
</nom-article>
</nom-chapter>
</nom-title>
</sec>
</root>
produces the wanted, correct result:
<root>
<nom-title>
<att>1.1</att>
<att>1.2</att>
<att>2.1</att>
<nom-chapter>
<att>1.1</att>
<att>1.2</att>
<nom-article>
<att>1.1</att>
</nom-article>
<nom-article>
<att>1.1</att>
<att>1.2</att>
<nom-item>
<data att="1.1"/>
</nom-item>
<nom-item>
<data att="1.2"/>
</nom-item>
</nom-article>
</nom-chapter>
<nom-chapter>
<att>2.1</att>
<att>1.1</att>
<nom-article>
<att>2.1</att>
</nom-article>
<nom-article>
<att>1.1</att>
</nom-article>
</nom-chapter>
</nom-title>
<nom-title>
<att>1.1</att>
<nom-chapter>
<att>1.1</att>
<nom-article>
<att>1.1</att>
</nom-article>
</nom-chapter>
</nom-title>
</root>
Explanation: Expressing three different Muenchian groupings as one, by dynamically constructing the name of the key for the actual grouping to be performed.
Remember: The key name is a string and when necessary (as in this case), the name can be dynamically constructed, or passed as a parameter.