Form multiple parent node for each of its descendants - xslt-1.0

Im quite new to xslt and breaking my head over this issue. Can anyone please help me with this?
Please find the input XML, I need to look for text L1 in id field of L node and search sublocation id and pit ref has text L1 and form new L1 node and arrange sublocation and pit under each L1 nodes.
<root>
<L Id="L1">
<test>ed</test>
<SubLocation id="L1S1">
<check>
<AId>1</AId>
</check>
<MD>
<UnitNumber>1</UnitNumber>
</MD>
</SubLocation>
<SubLocation id="L1S2">
<check>
<AId>2</AId>
</check>
<MD>
<UnitNumber>2</UnitNumber>
</MD>
</SubLocation>
</L>
<L Id="L2">
<test>ed</test>
<SubLocation id="L2S1">
<check>
<AId>1</AId>
</check>
<MD>
<UnitNumber>1</UnitNumber>
</MD>
</SubLocation>
<SubLocation id="L2S2">
<check>
<AId>2</AId>
</check>
<MD>
<UnitNumber>2</UnitNumber>
</MD>
</SubLocation>
</L>
<cp>
<current>
<Amt>20154.00</Amt>
</current>
<pi>
<pit ref="L1S1">
<value>1232</value>
</pit>
<pit ref="L1S2">
<value>12345</value>
</pit>
<pit ref="L1S3">
<value>12387</value>
</pit>
<pit ref="L2S1">
<value>1232</value>
</pit>
<pit ref="L2S2">
<value>12345</value>
</pit>
</pi>
</cp>
</root>
I need the o/p in following format
<root>
<L1>
<SubLocation id="L1S1">
<check>
<AId>1</AId>
</check>
<MD>
<UnitNumber>1</UnitNumber>
</MD>
</SubLocation>
<pit ref="L1S1">
<value>1232</value>
</pit>
</L1>
<L1>
<SubLocation id="L1S2">
<check>
<AId>2</AId>
</check>
<MD>
<UnitNumber>2</UnitNumber>
</MD>
</SubLocation>
<pit ref="L1S2">
<value>12345</value>
</pit>
</L1>
<L2>
<SubLocation id="L2S1">
<check>
<AId>1</AId>
</check>
<MD>
<UnitNumber>1</UnitNumber>
</MD>
</SubLocation>
<pit ref="L2S1">
<value>1232</value>
</pit>
</L2>
<L2>
<SubLocation id="L2S2">
<check>
<AId>2</AId>
</check>
<MD>
<UnitNumber>2</UnitNumber>
</MD>
</SubLocation>
<pit ref="L2S2">
<value>12345</value>
</pit>
</L2>
</root>
This is my xslt
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="cpbyid" match="pit" use="#ref"/>
<xsl:key name="slById" match="SubLocation" use="#id"/>
<xsl:key name="locbyId" match="L" use="#id"/>
<xsl:template match="#*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="L/*[#id]">
<L>
<xsl:value-of select="//L/#id"/>
<pifo>
<xsl:call-template name="subloc"></xsl:call-template>
<xsl:call-template name="identity"/>
</pifo>
</L>
</xsl:template>
<xsl:template match="pit/*[#ref]" name="subloc">
<inf>
<xsl:copy-of select="key('cpbyid', #id)"/>
<xsl:copy-of select="key('slById', #id)"/>
</inf>
</xsl:template>
</xsl:stylesheet>

I don't follow your description that well and I may be missing something. Is there a reason why you cannot do simply:
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="pit" match="pit" use="#ref" />
<xsl:template match="/root">
<xsl:copy>
<xsl:for-each select="L/SubLocation">
<xsl:element name="{../#Id}">
<xsl:copy-of select="."/>
<xsl:copy-of select="key('pit', #id)"/>
</xsl:element>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Related

Not able to get details of current node in template match 'L'

This xslt works perfectly fine but i need to get additional details under L node in the output generated, I am having issue forming test, testone nodes. The solution i tried is <xsl:apply-templates select="#*|node()|SL[#id = $ref]" mode="Loutput"/> including node() in this line but output will be wrong in this case.
Input xml as below
<root>
<L Id="L1">
<test>ed</test>
<testone><testtwo>ed</testtwo></testone>
<SL id="L1S1">
<check>
<AId>1</AId>
</check>
<MD>
<UnitNumber>1</UnitNumber>
</MD>
</SL>
<SL id="L1S2">
<check>
<AId>2</AId>
</check>
<MD>
<UnitNumber>2</UnitNumber>
</MD>
</SL>
</L>
<cp>
<current>
<Amt>20154.00</Amt>
</current>
<pi>
<pit ref="L1S1">
<value>123</value>
</pit>
<pit ref="L1S2">
<value>1232</value>
</pit>
</pi>
</cp>
</root>
Expected output should be:
<root>
<L Id="L1">
<test>ed</test>
<testone><testtwo>ed</testtwo></testone>
<SL id="L1S1">
<check>
<AId>1</AId>
</check>
<MD>
<UnitNumber>1</UnitNumber>
</MD>
</SL>
<pit ref="L1S1">
<value>123</value>
</pit>
</L>
<L Id="L1">
<test>ed</test>
<testone><testtwo>ed</testtwo></testone>
<SL id="L1S2">
<check>
<AId>2</AId>
</check>
<MD>
<UnitNumber>2</UnitNumber>
</MD>
</SL>
<pit ref="L1S2">
<value>1232</value>
</pit>
</L>
</root>
This xslt works fine with all my scenarios.
<xsl:key name="SLkey" match="SL" use="#id"/>
<xsl:key name="pitKey" match="pit" use="generate-id()"/>
<xsl:template match="root">
<xsl:copy>
<xsl:apply-templates select="#*|.//pit"/>
</xsl:copy>
</xsl:template>
<xsl:template match="pit">
<xsl:choose>
<!-- Is there an SL node match? -->
<xsl:when test="key('SLkey', #ref)[1]">
<xsl:apply-templates select="key('SLkey', #ref)[1]/.." mode="Loutput">
<xsl:with-param name="ref" select="#ref"/>
<xsl:with-param name="pitID" select="generate-id(.)"/>
</xsl:apply-templates>
</xsl:when>
<!-- Use the first L in the document. -->
<xsl:otherwise>
<xsl:apply-templates select="//L[1]" mode="Loutput">
<xsl:with-param name="ref" select="#ref"/>
<xsl:with-param name="pitID" select="generate-id(.)"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- ********************** -->
<!-- Loutput mode templates -->
<!-- ********************** -->
<xsl:template match="node()|#*" mode="Loutput">
<xsl:copy>
<xsl:apply-templates select="node()|#*" mode="Loutput"/>
</xsl:copy>
</xsl:template>
<xsl:template match="L" mode="Loutput">
<xsl:param name="ref"/>
<xsl:param name="pitID"/>
<xsl:copy>
<xsl:apply-templates select="#*|SL[#id = $ref]" mode="Loutput"/>
<xsl:apply-templates select="key('pitKey', $pitID)" mode="Loutput"/>
</xsl:copy>
</xsl:template>
This is one approach.
<xsl:key name="SLkey" match="SL" use="#id"/>
<xsl:key name="pitKey" match="pit" use="generate-id()"/>
<xsl:template match="root">
<xsl:copy>
<xsl:apply-templates select="#*|.//pit"/>
</xsl:copy>
</xsl:template>
<xsl:template match="pit">
<xsl:choose>
<!-- Is there an SL node match? -->
<xsl:when test="key('SLkey', #ref)[1]">
<xsl:apply-templates select="key('SLkey', #ref)[1]/.." mode="Loutput">
<xsl:with-param name="ref" select="#ref"/>
<xsl:with-param name="pitID" select="generate-id(.)"/>
</xsl:apply-templates>
</xsl:when>
<!-- Use the first L in the document. -->
<xsl:otherwise>
<xsl:apply-templates select="//L[1]" mode="Loutput">
<xsl:with-param name="ref" select="#ref"/>
<xsl:with-param name="pitID" select="generate-id(.)"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- ********************** -->
<!-- Loutput mode templates -->
<!-- ********************** -->
<xsl:template match="node()|#*" mode="Loutput">
<xsl:copy>
<xsl:apply-templates select="node()|#*" mode="Loutput"/>
</xsl:copy>
</xsl:template>
<xsl:template match="L" mode="Loutput">
<xsl:param name="ref"/>
<xsl:param name="pitID"/>
<xsl:copy>
<xsl:apply-templates select="#*|node()[local-name() != 'SL']" mode="Loutput"/>
<xsl:apply-templates select="SL[#id = $ref]" mode="Loutput"/>
<xsl:apply-templates select="key('pitKey', $pitID)" mode="Loutput"/>
</xsl:copy>
</xsl:template>

Having issue when there are identical keys in nodeset formed

My input xml is as below, I am facing issue when there are multiple identical keys present in a nodeset, its not forming proper output structure. I am using keys to form the nodeset by using ref attribute. I am making use of these <SL id="L1S1"> and <pit ref="L1S1"> to form nodesets. Id attribute of SL node(i.e <SL id="L1S1">) is formed using "L1" in <L Id="L1">. Also ref attribute of pit node(i.e <pit ref="L1S1">) is formed using "L1" in <L Id="L1">.
This solution works fine if I do not have multiple pit nodes with same reference number. I am using xslt1.0, and I have issue when multiple identical keys are found in nodeset.
Input xml as below
<root>
<L Id="L1">
<test>ed</test>
<SL id="L1S1">
<check>
<AId>1</AId>
</check>
</SL>
<SL id="L1S2">
<check>
<AId>2</AId>
</check>
</SL>
</L>
<cp>
<current>
<Amt>20154.00</Amt>
</current>
<pi>
<pit ref="L1S1">
<value>123</value>
</pit>
<pit ref="L1S1">
<value>234</value>
</pit>
<pit ref="L1S2">
<value>1232</value>
</pit>
</pi>
</cp>
</root>
Expected output should be:
<root>
<L Id="L1">
<SL id="L1S1">
<check>
<AId>1</AId>
</check>
</SL>
<pit ref="L1S1">
<value>123</value>
</pit>
</L>
<L Id="L1">
<SL id="L1S1">
<check>
<AId>1</AId>
</check>
</SL>
<pit ref="L1S1">
<value>234</value>
</pit>
</L>
<L Id="L1">
<SL id="L1S2">
<check>
<AId>2</AId>
</check>
</SL>
<pit ref="L1S2">
<value>1232</value>
</pit>
</L>
</root>
<xsl:key name="pit-SL" match="pit" use="#ref" />
<xsl:key name="pit-L" match="pit" use="substring(#ref,1,2)" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="L[SL]">
<xsl:apply-templates select="SL"/>
</xsl:template>
<xsl:template match="SL">
<L>
<xsl:copy-of select="parent::L/#Id"/>
<xsl:copy>
<xsl:copy-of select="#id"/>
<xsl:apply-templates select="node()"/>
<xsl:copy-of select="key('pit-SL',#id)"/>
</xsl:copy>
</L>
</xsl:template>
<xsl:template match="L[not(SL)]">
<xsl:apply-templates select="key('pit-L',#Id)">
<xsl:with-param name="L" select="."/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="pit">
<xsl:param name="L"/>
<L>
<xsl:copy-of select="$L/#Id"/>
<xsl:copy-of select="."/>
</L>
</xsl:template>
<xsl:template match="cp"/>
AFAICT, you could do:
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="pit" match="pit" use="#ref" />
<xsl:template match="/root">
<xsl:copy>
<xsl:for-each select="L">
<xsl:variable name="Id" select="#Id" />
<xsl:for-each select="SL">
<xsl:variable name="SL" select="." />
<xsl:for-each select="key('pit', #id)">
<L>
<xsl:copy-of select="$Id"/>
<xsl:copy-of select="$SL"/>
<xsl:copy-of select="."/>
</L>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Issue in forming node structure when multiple identical keys found in a nodeset

Scenario 1: L node having child node SL
Scenario 2: L node with no child node SL
Scenario 3: L node having child node SL and having multiple pit elements having attribute ref identical.
I need to form multiple L nodes if text "L1" () is found at other nodes like and . Id attribute of SL node(i.e ) is formed using "L1" in . Also ref attribute of pit node(i.e ) is formed using "L1" in , I need to check whether "L1" is present in either id attribute of SL or ref attribute of pit and form the desired output.
Input xml as below
<root>
<L Id="L1">
<test>ed</test>
<SL id="L1S1">
<check>
<AId>1</AId>
</check>
<MD>
<UnitNumber>1</UnitNumber>
</MD>
</SL>
<SL id="L1S2">
<check>
<AId>2</AId>
</check>
<MD>
<UnitNumber>2</UnitNumber>
</MD>
</SL>
</L>
<cp>
<current>
<Amt>20154.00</Amt>
</current>
<pi>
<pit ref="L1S1">
<value>123</value>
</pit>
<pit ref="L1S2">
<value>1232</value>
</pit>
</pi>
</cp>
</root>
Expected output should be:
<root>
<L Id="L1">
<SL id="L1S1">
<check>
<AId>1</AId>
</check>
<MD>
<UnitNumber>1</UnitNumber>
</MD>
</SL>
<pit ref="L1S1">
<value>123</value>
</pit>
</L>
<L Id="L1">
<SL id="L1S2">
<check>
<AId>2</AId>
</check>
<MD>
<UnitNumber>2</UnitNumber>
</MD>
</SL>
<pit ref="L1S2">
<value>1232</value>
</pit>
</L>
</root>
<root>
<L Id="L1">
<test>ed</test>
</L>
<cp>
<current>
<Amt>20154.00</Amt>
</current>
<pi>
<pit ref="L1S1">
<value>123</value>
</pit>
<pit ref="L1S2">
<value>1232</value>
</pit>
</pi>
</cp>
</root>
Expected output should be:
<root>
<L Id="L1">
<pit ref="L1S1">
<value>123</value>
</pit>
</L>
<L Id="L1">
<pit ref="L1S2">
<value>1232</value>
</pit>
</L>
</root>
Scenario 3:
Input xml as below
<root>
<L Id="L1">
<test>ed</test>
<SL id="L1S1">
<check>
<AId>1</AId>
</check>
<MD>
<UnitNumber>1</UnitNumber>
</MD>
</SL>
<SL id="L1S2">
<check>
<AId>2</AId>
</check>
<MD>
<UnitNumber>2</UnitNumber>
</MD>
</SL>
</L>
<cp>
<current>
<Amt>20154.00</Amt>
</current>
<pi>
<pit ref="L1S1">
<value>123</value>
</pit>
<pit ref="L1S1">
<value>234</value>
</pit>
<pit ref="L1S2">
<value>1232</value>
</pit>
<pit ref="L1S2">
<value>1</value>
</pit>
</pi>
</cp>
</root>
Expected output should be:
<root>
<L Id="L1">
<SL id="L1S1">
<check>
<AId>1</AId>
</check>
<MD>
<UnitNumber>1</UnitNumber>
</MD>
</SL>
<pit ref="L1S1">
<value>123</value>
</pit>
</L>
<L Id="L1">
<SL id="L1S1">
<check>
<AId>1</AId>
</check>
<MD>
<UnitNumber>1</UnitNumber>
</MD>
</SL>
<pit ref="L1S1">
<value>234</value>
</pit>
</L>
<L Id="L1">
<SL id="L1S2">
<check>
<AId>2</AId>
</check>
<MD>
<UnitNumber>2</UnitNumber>
</MD>
</SL>
<pit ref="L1S2">
<value>1232</value>
</pit>
</L>
<L Id="L1">
<SL id="L1S2">
<check>
<AId>2</AId>
</check>
<MD>
<UnitNumber>2</UnitNumber>
</MD>
</SL>
<pit ref="L1S2">
<value>1</value>
</pit>
</L>
</root>
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="pit-SL" match="pit" use="#ref" />
<xsl:key name="pit-L" match="pit" use="substring(#ref,1,2)" />
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="L[SL]">
<xsl:apply-templates select="SL"/>
</xsl:template>
<xsl:template match="SL">
<L>
<xsl:copy-of select="parent::L/#Id"/>
<xsl:copy>
<xsl:copy-of select="#id"/>
<xsl:apply-templates select="node()"/>
<xsl:copy-of select="key('pit-SL',#id)"/>
</xsl:copy>
</L>
</xsl:template>
<xsl:template match="L[not(SL)]">
<xsl:apply-templates select="key('pit-L',#Id)">
<xsl:with-param name="L" select="."/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="pit">
<xsl:param name="L"/>
<L>
<xsl:copy-of select="$L/#Id"/>
<xsl:copy-of select="."/>
</L>
</xsl:template>
<xsl:template match="cp"/>
</xsl:stylesheet>
Iam facing issue in 3rd scenario, when there are multiple identical pit ref keys.
Here is an approach.
<xsl:key name="SLkey" match="SL" use="#id"/>
<xsl:key name="pitKey" match="pit" use="generate-id()"/>
<xsl:template match="root">
<xsl:copy>
<xsl:apply-templates select="#*|.//pit"/>
</xsl:copy>
</xsl:template>
<xsl:template match="pit">
<xsl:choose>
<!-- Is there an SL node match? -->
<xsl:when test="key('SLkey', #ref)[1]">
<xsl:apply-templates select="key('SLkey', #ref)[1]/.." mode="Loutput">
<xsl:with-param name="ref" select="#ref"/>
<xsl:with-param name="pitID" select="generate-id(.)"/>
</xsl:apply-templates>
</xsl:when>
<!-- Use the first L in the document. -->
<xsl:otherwise>
<xsl:apply-templates select="//L[1]" mode="Loutput">
<xsl:with-param name="ref" select="#ref"/>
<xsl:with-param name="pitID" select="generate-id(.)"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- ********************** -->
<!-- Loutput mode templates -->
<!-- ********************** -->
<xsl:template match="node()|#*" mode="Loutput">
<xsl:copy>
<xsl:apply-templates select="node()|#*" mode="Loutput"/>
</xsl:copy>
</xsl:template>
<xsl:template match="L" mode="Loutput">
<xsl:param name="ref"/>
<xsl:param name="pitID"/>
<xsl:copy>
<xsl:apply-templates select="#*|SL[#id = $ref]" mode="Loutput"/>
<xsl:apply-templates select="key('pitKey', $pitID)" mode="Loutput"/>
</xsl:copy>
</xsl:template>

xslt 1.0 combinate two segments

how to combinate two or more segments to one segment at xslt 1.0?
I have two cases.
Case1:
If "QUALIFIER" at GRP/TXT is the same (for example: AAA) combinate this to one.
Correct:
QUALIFIER: AAA
TEXT: Test AAA rtetertertret
Case2:
Same should be at GRP/ITEM/TXT (for example: LIN)
Correct:
QUALIFIER: LIN
TEXT: Test LIN sdfsdfsfsf
<?xml version="1.0"?>
<SEEDELFOR>
<Test/>
<CNT>
<TRANSMISSION_DATE></TRANSMISSION_DATE>
<TRANSMISSION_TIME></TRANSMISSION_TIME>
<INTERCHANGE_CONTROL_NUMBER></INTERCHANGE_CONTROL_NUMBER>
<SENDER></SENDER>
<SENDER_QUALIFIER></SENDER_QUALIFIER>
<RECEIVER></RECEIVER>
<RECEIVER_QUALIFIER></RECEIVER_QUALIFIER>
<SYNTAX_IDENTIFIER></SYNTAX_IDENTIFIER>
<SYNTAX_VERSION></SYNTAX_VERSION>
<BGM></BGM>
<GRP>
<IDENTIFIER_BY></IDENTIFIER_BY>
<IDENTIFIER_SU></IDENTIFIER_SU>
<DATE_4></DATE_4>
<REF_ON></REF_ON>
<ADD>
<QUALIFIER></QUALIFIER>
<IDENTIFIER></IDENTIFIER>
<AGENCY_CODE></AGENCY_CODE>
<CONTACT>
<QUALIFIER></QUALIFIER>
<NUMBER></NUMBER>
</CONTACT>
<CONTACT>
<QUALIFIER></QUALIFIER>
<NUMBER></NUMBER>
</CONTACT>
<CONTACT>
<QUALIFIER></QUALIFIER>
<NUMBER></NUMBER>
</CONTACT>
</ADD>
<ADD>
<QUALIFIER></QUALIFIER>
<IDENTIFIER></IDENTIFIER>
<AGENCY_CODE></AGENCY_CODE>
</ADD>
<TXT>
<QUALIFIER>AAA</QUALIFIER>
<TEXT>Test AAA</TEXT>
</TXT>
<TXT>
<QUALIFIER>AAA</QUALIFIER>
<TEXT>rtetertertret</TEXT>
</TXT>
<TRANSPORT_DETAILS>
<ADDITIONAL_DETAILS>
<QUALIFIER></QUALIFIER>
<DETAILS></DETAILS>
</ADDITIONAL_DETAILS>
</TRANSPORT_DETAILS>
<TRANSPORT_DETAILS>
<ADDITIONAL_DETAILS>
<QUALIFIER></QUALIFIER>
<DETAILS></DETAILS>
</ADDITIONAL_DETAILS>
</TRANSPORT_DETAILS>
<TRANSPORT_DETAILS>
<ADDITIONAL_DETAILS>
<QUALIFIER></QUALIFIER>
<DETAILS></DETAILS>
</ADDITIONAL_DETAILS>
</TRANSPORT_DETAILS>
<ITEM>
<ITEM_NUMBER_SA></ITEM_NUMBER_SA>
<QUANTITY></QUANTITY>
<QUANTITY_UNIT></QUANTITY_UNIT>
<LINE_ITEM_NUMBER>2</LINE_ITEM_NUMBER>
<TXT>
<QUALIFIER>LIN</QUALIFIER>
<TEXT>Test LIN</TEXT>
</TXT>
</ITEM>
<ITEM>
<ITEM_NUMBER_SA></ITEM_NUMBER_SA>
<QUANTITY></QUANTITY>
<QUANTITY_UNIT></QUANTITY_UNIT>
<LINE_ITEM_NUMBER>1</LINE_ITEM_NUMBER>
<TXT>
<QUALIFIER>LIN</QUALIFIER>
<TEXT>Test LIN</TEXT>
</TXT>
<TXT>
<QUALIFIER>LIN</QUALIFIER>
<TEXT>sdfsdfsfsf</TEXT>
</TXT>
</ITEM>
</GRP>
</CNT>
</SEEDELFOR>
Correct output should be:
<?xml version="1.0"?>
<SEEDELFOR>
<Test/>
<CNT>
<TRANSMISSION_DATE></TRANSMISSION_DATE>
<TRANSMISSION_TIME></TRANSMISSION_TIME>
<INTERCHANGE_CONTROL_NUMBER></INTERCHANGE_CONTROL_NUMBER>
<SENDER></SENDER>
<SENDER_QUALIFIER></SENDER_QUALIFIER>
<RECEIVER></RECEIVER>
<RECEIVER_QUALIFIER></RECEIVER_QUALIFIER>
<SYNTAX_IDENTIFIER></SYNTAX_IDENTIFIER>
<SYNTAX_VERSION></SYNTAX_VERSION>
<BGM></BGM>
<GRP>
<IDENTIFIER_BY></IDENTIFIER_BY>
<IDENTIFIER_SU></IDENTIFIER_SU>
<DATE_4></DATE_4>
<REF_ON></REF_ON>
<ADD>
<QUALIFIER></QUALIFIER>
<IDENTIFIER></IDENTIFIER>
<AGENCY_CODE></AGENCY_CODE>
<CONTACT>
<QUALIFIER></QUALIFIER>
<NUMBER></NUMBER>
</CONTACT>
<CONTACT>
<QUALIFIER></QUALIFIER>
<NUMBER></NUMBER>
</CONTACT>
<CONTACT>
<QUALIFIER></QUALIFIER>
<NUMBER></NUMBER>
</CONTACT>
</ADD>
<ADD>
<QUALIFIER></QUALIFIER>
<IDENTIFIER></IDENTIFIER>
<AGENCY_CODE></AGENCY_CODE>
</ADD>
<TXT>
<QUALIFIER>AAA</QUALIFIER>
<TEXT>Test AAA rtetertertret</TEXT>
</TXT>
<TRANSPORT_DETAILS>
<ADDITIONAL_DETAILS>
<QUALIFIER></QUALIFIER>
<DETAILS></DETAILS>
</ADDITIONAL_DETAILS>
</TRANSPORT_DETAILS>
<TRANSPORT_DETAILS>
<ADDITIONAL_DETAILS>
<QUALIFIER></QUALIFIER>
<DETAILS></DETAILS>
</ADDITIONAL_DETAILS>
</TRANSPORT_DETAILS>
<TRANSPORT_DETAILS>
<ADDITIONAL_DETAILS>
<QUALIFIER></QUALIFIER>
<DETAILS></DETAILS>
</ADDITIONAL_DETAILS>
</TRANSPORT_DETAILS>
<ITEM>
<ITEM_NUMBER_SA></ITEM_NUMBER_SA>
<QUANTITY></QUANTITY>
<QUANTITY_UNIT></QUANTITY_UNIT>
<LINE_ITEM_NUMBER>2</LINE_ITEM_NUMBER>
<TXT>
<QUALIFIER>LIN</QUALIFIER>
<TEXT>Test LIN</TEXT>
</TXT>
</ITEM>
<ITEM>
<ITEM_NUMBER_SA></ITEM_NUMBER_SA>
<QUANTITY></QUANTITY>
<QUANTITY_UNIT></QUANTITY_UNIT>
<LINE_ITEM_NUMBER>1</LINE_ITEM_NUMBER>
<TXT>
<QUALIFIER>LIN</QUALIFIER>
<TEXT>Test LIN sdfsdfsfsf</TEXT>
</TXT>
</ITEM>
</GRP>
</CNT>
</SEEDELFOR>
Best regards
Julian
It can be achievable as following in XSLT 1.0:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:key name="qualifierKey" match="/SEEDELFOR/CNT/GRP//TXT" use="QUALIFIER" />
<xsl:key name="qualifierTextKey" match="/SEEDELFOR/CNT/GRP//TXT" use="concat(QUALIFIER, '|', TEXT)" />
<xsl:key name="itemTxtKey" match="/SEEDELFOR/CNT/GRP/ITEM/TXT" use="concat(generate-id(parent::*), QUALIFIER, '|', TEXT)" />
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*" />
</xsl:copy>
</xsl:template>
<xsl:template match="TXT[position() > 1]" />
<xsl:template match="/SEEDELFOR/CNT/GRP/ITEM/TXT[following-sibling::*[1]][generate-id(.) = generate-id(key('itemTxtKey', concat(generate-id(parent::*), QUALIFIER, '|', TEXT))[1])]
| /SEEDELFOR/CNT/GRP/TXT[following-sibling::*[1]][generate-id() = generate-id(key('qualifierKey',QUALIFIER)[1])]">
<TXT>
<QUALIFIER>
<xsl:value-of select="normalize-space(QUALIFIER)" />
</QUALIFIER>
<TEXT>
<xsl:variable name="count" select="count(key('qualifierKey',QUALIFIER)[generate-id() = generate-id(key('qualifierTextKey', concat(QUALIFIER, '|', TEXT))[1])])" />
<xsl:for-each select="key('qualifierKey',QUALIFIER)[generate-id() = generate-id(key('qualifierTextKey', concat(QUALIFIER, '|', TEXT))[1])]">
<xsl:value-of select="normalize-space(TEXT)" />
<xsl:if test="$count != position()"><xsl:value-of select="' '"></xsl:value-of></xsl:if>
</xsl:for-each>
</TEXT>
</TXT>
</xsl:template>
</xsl:stylesheet>
See output here: http://xsltfiddle.liberty-development.net/jyRYYib/2

Accessing current node in predicate with xsl:for-each

I'm stuck finding out how I can access the current node whilst iterating over a collection of nodes with xsL:for-each. This is my XML:
<events>
<event>
<date>
<year>2012</year>
<month>July</month>
</date>
<description>...</description>
</event>
<!-- more events -->
</events>
What I try to achieve is an HTML-representation like this:
<h2>2012</h2>
<dl>
<dt>July</dt>
<dd>One of these for every event with year=2012 and month=July</dd>
<dt>August</dt>
<!-- ... -->
</dl>
<h2>2013</h2>
<!-- ... -->
I'm using an XPath-expression to get all distinct years and then iterate over them calling a template called year with parameters $year and $events. Getting the value for $year is easy, but I'm struggling finding the right events. The following won't work, probably because . in the second predicate refers to the event being tested for the predicate. But how to access the year in there?
<xsl:template match="events">
<xsl:for-each select="event[not(date/year=preceding-sibling::event/date/year)]/date/year">
<xsl:call-template name="year">
<xsl:with-param name="year" select="." />
<xsl:with-param name="events" select="event[date/year=.]" />
</xsl:call-template>
</xsl:for-each>
</xsl:template>
Many thanks in advance!
PS: Must work with XPath and XSLT 1.0.
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="kYear" match="year" use="."/>
<xsl:key name="kEventByMonthYear" match="event"
use="string(date)"/>
<xsl:key name="kMonthByMonthYear" match="month"
use="string(..)"/>
<xsl:key name="kMonthByYear" match="month"
use="../year"/>
<xsl:template match="/*">
<xsl:for-each select=
"*/date/year
[generate-id() = generate-id(key('kYear', .)[1])]
">
<h2><xsl:value-of select="."/></h2>
<dl>
<xsl:apply-templates select=
"key('kMonthByYear', current())
[generate-id()
=
generate-id(key('kMonthByMonthYear',
string(..)
)[1]
)
]"/>
</dl>
</xsl:for-each>
</xsl:template>
<xsl:template match="month">
<dt><xsl:value-of select="."/></dt>
<xsl:for-each select=
"key('kEventByMonthYear', string(current()/..))">
<dd><xsl:value-of select="description"/></dd>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
when applied on the following XML document:
<events>
<event>
<date>
<year>2012</year>
<month>January</month>
</date>
<description>Jan1</description>
</event>
<event>
<date>
<year>2012</year>
<month>January</month>
</date>
<description>Jan2</description>
</event>
<event>
<date>
<year>2012</year>
<month>March</month>
</date>
<description>Mar1</description>
</event>
<event>
<date>
<year>2012</year>
<month>March</month>
</date>
<description>Mar2</description>
</event>
<event>
<date>
<year>2012</year>
<month>March</month>
</date>
<description>Mar3</description>
</event>
<event>
<date>
<year>2012</year>
<month>July</month>
</date>
<description>Jul1</description>
</event>
<event>
<date>
<year>2012</year>
<month>July</month>
</date>
<description>Jul2</description>
</event>
<event>
<date>
<year>2012</year>
<month>September</month>
</date>
<description>Sep1</description>
</event>
<event>
<date>
<year>2012</year>
<month>October</month>
</date>
<description>Oct1</description>
</event>
<event>
<date>
<year>2012</year>
<month>October</month>
</date>
<description>Oct2</description>
</event>
<event>
<date>
<year>2012</year>
<month>November</month>
</date>
<description>Nov1</description>
</event>
<event>
<date>
<year>2012</year>
<month>November</month>
</date>
<description>Nov2</description>
</event>
<event>
<date>
<year>2012</year>
<month>December</month>
</date>
<description>Dec1</description>
</event>
<event>
<date>
<year>2012</year>
<month>December</month>
</date>
<description>Dec2</description>
</event>
<event>
<date>
<year>2012</year>
<month>December</month>
</date>
<description>Dec3</description>
</event>
<event>
<date>
<year>2013</year>
<month>January</month>
</date>
<description>Jan1</description>
</event>
<event>
<date>
<year>2013</year>
<month>January</month>
</date>
<description>Jan2</description>
</event>
</events>
produces the wanted, correct result:
<h2>2012</h2>
<dl>
<dt>January</dt>
<dd>Jan1</dd>
<dd>Jan2</dd>
<dt>March</dt>
<dd>Mar1</dd>
<dd>Mar2</dd>
<dd>Mar3</dd>
<dt>July</dt>
<dd>Jul1</dd>
<dd>Jul2</dd>
<dt>September</dt>
<dd>Sep1</dd>
<dt>October</dt>
<dd>Oct1</dd>
<dd>Oct2</dd>
<dt>November</dt>
<dd>Nov1</dd>
<dd>Nov2</dd>
<dt>December</dt>
<dd>Dec1</dd>
<dd>Dec2</dd>
<dd>Dec3</dd>
</dl>
<h2>2013</h2>
<dl>
<dt>January</dt>
<dd>Jan1</dd>
<dd>Jan2</dd>
</dl>
Explanation:
Proper use of the Muenchian method for grouping -- with composite grouping keys.
#Dimitre Novatchev's answer is the more elaborate one, but I found another possibility I'd like to share. It doesn't depend on keys and therefore is a bit more "newbie-friendly". On the other hand it too doesn't solve the original "accessing current node of an iteration" problem:
<?xml version="1.0" encoding="utf-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="events">
<xsl:for-each select="event[not(date/year=preceding-sibling::event/date/year)]/date/year">
<xsl:call-template name="year">
<xsl:with-param name="year" select="." />
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="year">
<xsl:param name="year" />
<h2><xsl:value-of select="$year" /></h2>
<dl class="dl-horizontal">
<xsl:for-each select="//event[date/year=$year][not(date/month=preceding-sibling::event[date/year=$year]/date/month)]/date/month">
<xsl:call-template name="month">
<xsl:with-param name="month" select="." />
<xsl:with-param name="year" select="$year" />
</xsl:call-template>
</xsl:for-each>
</dl>
</xsl:template>
<xsl:template name="month">
<xsl:param name="month" />
<xsl:param name="year" />
<dt><xsl:value-of select="$month" /></dt>
<xsl:for-each select="//event[date/year=$year][date/month=$month]">
<xsl:call-template name="event">
<xsl:with-param name="event" select="." />
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="event">
<xsl:param name="event" />
<dd><xsl:copy-of select="description/node()" /></dd>
</xsl:template>
</xsl:transform>