Duplicate in key (Muenchian Grouping) - xslt

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

Related

Remove duplicates but only on parent level XSLT 1.0

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>

xslt 1 : check if node contains any value from list

I need to tranform a XML document from one format to a other, and that is all dandy. Now the hard part is that I need to check all lines for a status code, and need to return true/false depend if any code element have any of this codes.
<xml>
<line>
<id>1</id>
<code>109</code>
</line>
<line>
<id>2</id>
<code>065</code>
</line>
<line>
<id>3</id>
<code>405</code>
</line>
<line>
<id>4</id>
<code>101</code>
</line>
</xml>
The document I tranform to keep a copy of all line element, but have a extra field, where is set to true/false depend if the any code is in the list.
So I need to compare this list of data to every code and return true if just one of them is in the list
"101","102","103","104","105","106","107","108","109","110","111"
Is there any fix mode to make this so I don't need 11 compare stament ?
Ohh and the output look some thing like
<System>
<Route>true</Route> <!-- will be false if the <code> from the first document is not in the list of elements -->
<Status>
<ID>1</ID>
<Code>109</Code>
</Status>
<Status>
<ID>2</ID>
<Code>065</Code>
</Status>
<Status>
<ID>3</ID>
<Code>405</Code>
</Status>
<Status>
<ID>4</ID>
<Code>101</Code>
</Status>
<System>
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:param name="pCodeList" select="'101,102,103,104,105,106,107,108,109,110,111'"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<System>
<Route>
<xsl:value-of select=
"boolean(/*/*/code
[contains(concat(',', $pCodeList, ','), concat(',', ., ',')
)
]
)"/>
</Route>
<xsl:apply-templates/>
</System>
</xsl:template>
<xsl:template match="line">
<Status><xsl:apply-templates/></Status>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<xml>
<line>
<id>1</id>
<code>109</code>
</line>
<line>
<id>2</id>
<code>065</code>
</line>
<line>
<id>3</id>
<code>405</code>
</line>
<line>
<id>4</id>
<code>101</code>
</line>
</xml>
produces the wanted, correct result:
<System>
<Route>true</Route>
<Status>
<id>1</id>
<code>109</code>
</Status>
<Status>
<id>2</id>
<code>065</code>
</Status>
<Status>
<id>3</id>
<code>405</code>
</Status>
<Status>
<id>4</id>
<code>101</code>
</Status>
</System>
When the same transformation (above) is applied on this XML document:
<xml>
<line>
<id>1</id>
<code>509</code>
</line>
<line>
<id>2</id>
<code>065</code>
</line>
<line>
<id>3</id>
<code>405</code>
</line>
<line>
<id>4</id>
<code>501</code>
</line>
</xml>
it again produces the wanted, correct result:
<System>
<Route>false</Route>
<Status>
<id>1</id>
<code>509</code>
</Status>
<Status>
<id>2</id>
<code>065</code>
</Status>
<Status>
<id>3</id>
<code>405</code>
</Status>
<Status>
<id>4</id>
<code>501</code>
</Status>
</System>

XSLT grouping multiple levels [duplicate]

I'm trying to group the input below by the destination and assortment values using muenchian-grouping which is new for me so I'm not sure how to do it properly. The input files will be much larger than this so performance is important.
<?xml version="1.0"?>
<ns0:Data xmlns:ns0="http://BizTalk_Projects.input">
<transports>
<destination>destination 1</destination>
<assortment>Volvo_GA961</assortment>
<quantity>10</quantity>
</transports>
<transports>
<destination>destination 1</destination>
<assortment>Volvo_GA961</assortment>
<quantity>15</quantity>
</transports>
<transports>
<destination>destination 1</destination>
<assortment>Volvo_GA969</assortment>
<quantity>15</quantity>
</transports>
<transports>
<destination>destination 1</destination>
<assortment>Volvo_GA972</assortment>
<quantity>5</quantity>
</transports>
<transports>
<destination>destination 1</destination>
<assortment>Volvo_SA980</assortment>
<quantity>20</quantity>
</transports>
<transports>
<destination>destination 2</destination>
<assortment>Volvo_GA960</assortment>
<quantity>10</quantity>
</transports>
<transports>
<destination>destination 1</destination>
<assortment>Nissan_GA963</assortment>
<quantity>5</quantity>
</transports>
<transports>
<destination>destination 1</destination>
<assortment>Nissan_GA963</assortment>
<quantity>5</quantity>
</transports>
</ns0:Data>
Expected output:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:Destinations xmlns:ns0="http://BizTalk_Projects.output">
<Destination>
<name>destination 1</name>
<assortment>
<name>Volvo_GA</name>
<row>
<type>sumPerAssortment</type>
<id>961</id>
<totalQuantity>25</totalQuantity>
<region>1</region>
</row>
<row>
<type>sumPerAssortment</type>
<id>969</id>
<totalQuantity>15</totalQuantity>
<region>1</region>
</row>
<row>
<type>sumPerAssortment</type>
<id>972</id>
<totalQuantity>5</totalQuantity>
<region>2</region>
</row>
<row>
<type>sumPerRegion</type>
<id />
<totalQuantity>40</totalQuantity>
<region>1</region>
</row>
<row>
<type>sumPerRegion</type>
<id />
<totalQuantity>5</totalQuantity>
<region>2</region>
</row>
<row>
<type>totalSum</type>
<id />
<totalQuantity>45</totalQuantity>
<region />
</row>
</assortment>
<assortment>
<name>Volvo_SA</name>
<row>
<type>sumPerAssortment</type>
<id>980</id>
<totalQuantity>20</totalQuantity>
<region>3</region>
</row>
<row>
<type>sumPerRegion</type>
<id />
<totalQuantity>20</totalQuantity>
<region>3</region>
</row>
<row>
<type>totalSum</type>
<id />
<totalQuantity>20</totalQuantity>
<region />
</row>
</assortment>
<assortment>
<name>Nissan_GA</name>
<row>
<type>sumPerAssortment</type>
<id>963</id>
<totalQuantity>10</totalQuantity>
<region>1</region>
</row>
<row>
<type>sumPerRegion</type>
<id />
<totalQuantity>10</totalQuantity>
<region>1</region>
</row>
<row>
<type>totalSum</type>
<id />
<totalQuantity>10</totalQuantity>
<region />
</row>
</assortment>
</Destination>
<Destination>
<name>destination 2</name>
<assortment>
<name>Volvo_GA</name>
<row>
<type>sumPerAssortment</type>
<id>960</id>
<totalQuantity>10</totalQuantity>
<region>1</region>
</row>
<row>
<type>sumPerRegion</type>
<id />
<totalQuantity>10</totalQuantity>
<region>1</region>
</row>
<row>
<type>totalSum</type>
<id />
<totalQuantity>10</totalQuantity>
<region />
</row>
</assortment>
</Destination>
</ns0:Destinations>
Note:
assortment number starting with 96 = region 1
assortment number starting with 97 = region 2
assortment number starting with 98 = region 3
Start of my XSLT:
<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var"
exclude-result-prefixes="msxsl var s0"
version="1.0"
xmlns:s0="http://BizTalk_Projects.input"
xmlns:ns0="http://BizTalk_Projects.output">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
<xsl:key name="destinationKey" match="transports" use="destination"/>
<xsl:template match="/">
<xsl:apply-templates select="/s0:Data" />
</xsl:template>
<xsl:template match="/s0:Data">
<ns0:Destinations>
<xsl:for-each select="transports[count(. | key('destinationKey',destination)[1]) = 1]">
<Destination>
<name>
<xsl:value-of select="destination/text()" />
</name>
<xsl:for-each select="key('destinationKey',destination)">
<assortment>
<name>
<xsl:value-of select="substring(assortment/text(),1,string-length(assortment)-3)" />
</name>
</assortment>
</xsl:for-each>
</Destination>
</xsl:for-each>
</ns0:Destinations>
</xsl:template>
</xsl:stylesheet>
With this code, I'm getting this output (duplicate rows, but correct assortments for each destination);
<ns0:Destinations xmlns:ns0="http://BizTalk_Projects.output">
<Destination>
<name>destination 1</name>
<assortment>
<name>Volvo_GA</name>
</assortment>
<assortment>
<name>Volvo_GA</name>
</assortment>
<assortment>
<name>Volvo_GA</name>
</assortment>
<assortment>
<name>Volvo_GA</name>
</assortment>
<assortment>
<name>Volvo_SA</name>
</assortment>
<assortment>
<name>Nissan_GA</name>
</assortment>
<assortment>
<name>Nissan_GA</name>
</assortment>
</Destination>
<Destination>
<name>destination 2</name>
<assortment>
<name>Volvo_GA</name>
</assortment>
</Destination>
</ns0:Destinations>
Any suggestions on how I can solve this? Help is very appreciated!
It's difficult to see how exactly the output relates to the input. Try this as your starting point:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="transports-by-destination" match="transports" use="destination" />
<xsl:key name="transports-by-assortment" match="transports" use="concat(destination, '|', assortment)" />
<xsl:template match="/*">
<xsl:copy>
<!-- for each unique destination -->
<xsl:for-each select="transports[count(. | key('transports-by-destination', destination)[1]) = 1]">
<Destination>
<name>
<xsl:value-of select="destination"/>
</name>
<xsl:variable name="group" select="key('transports-by-destination', destination)" />
<!-- for each unique assortment in this destination -->
<xsl:for-each select="$group[count(. | key('transports-by-assortment', concat(destination, '|', assortment))[1]) = 1]">
<assortment>
<name>
<xsl:value-of select="assortment"/>
</name>
<!-- process this subgroup -->
<xsl:for-each select="key('transports-by-assortment', concat(destination, '|', assortment))" >
<row>
<!-- not sure what goes in here -->
<totalQuantity>
<xsl:value-of select="quantity"/>
</totalQuantity>
</row>
</xsl:for-each>
</assortment>
</xsl:for-each>
</Destination>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

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>

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.