Reputation: 17
I have following input XML. The successive E_Records are optional and it should be populated into L_Record. I have written the below XSLT coding. Is there any changes should i have to do?
Input XML
<?xml version="1.0" encoding="UTF-8"?>
<Record>
<H_Record>
<Rec_Type>H</Rec_Type>
</H_Record>
<C_Record>
<Rec_Type>C</Rec_Type>
</C_Record>
<L_Record>
<Rec_Type>L</Rec_Type>
<L_Level>2</L_Level>
</L_Record>
<E_Record>
<Rec_Type>E</Rec_Type>
<E_Qty>3</E_Qty>
</E_Record>
<E_Record>
<Rec_Type>E</Rec_Type>
<E_Qty>4</E_Qty>
</E_Record>
<L_Record>
<Rec_Type>L</Rec_Type>
<L_Level>2</L_Level>
</L_Record>
<R_Record>
<Rec_Type>R</Rec_Type>
</R_Record>
</Record>
<Record>
<H_Record>
<Rec_Type>H</Rec_Type>
</H_Record>
<C_Record>
<Rec_Type>C</Rec_Type>
</C_Record>
<L_Record>
<Rec_Type>L</Rec_Type>
<L_Level>2</L_Level>
</L_Record>
<L_Record>
<Rec_Type>L</Rec_Type>
<L_Level>2</L_Level>
</L_Record>
<E_Record>
<Rec_Type>E</Rec_Type>
<E_Qty>1</E_Qty>
</E_Record>
<E_Record>
<Rec_Type>E</Rec_Type>
<E_Qty>2</E_Qty>
</E_Record>
<L_Record>
<Rec_Type>L</Rec_Type>
<L_Level>2</L_Level>
</L_Record>
<E_Record>
<Rec_Type>E</Rec_Type>
<E_Qty>5</E_Qty>
</E_Record>
<E_Record>
<Rec_Type>E</Rec_Type>
<E_Qty>6</E_Qty>
</E_Record>
<R_Record>
<Rec_Type>R</Rec_Type>
</R_Record>
</Record>
The Output XML i am expecting is
<Record>
<H_Record>
<Rec_Type>H</Rec_Type>
</H_Record>
<C_Record>
<Rec_Type>C</Rec_Type>
</C_Record>
<L_Record>
<Rec_Type>L</Rec_Type>
<L_Level>2</L_Level>
<E_Record>
<Rec_Type>E</Rec_Type>
<E_Qty>3</E_Qty>
</E_Record>
<E_Record>
<Rec_Type>E</Rec_Type>
<E_Qty>4</E_Qty>
</E_Record>
</L_Record>
<L_Record>
<Rec_Type>L</Rec_Type>
<L_Level>2</L_Level>
</L_Record>
<R_Record>
<Rec_Type>R</Rec_Type>
</R_Record>
</Record>
<Record>
<H_Record>
<Rec_Type>H</Rec_Type>
</H_Record>
<C_Record>
<Rec_Type>C</Rec_Type>
</C_Record>
<L_Record>
<Rec_Type>L</Rec_Type>
<L_Level>2</L_Level>
</L_Record>
<L_Record>
<Rec_Type>L</Rec_Type>
<L_Level>2</L_Level>
<E_Record>
<Rec_Type>E</Rec_Type>
<E_Qty>1</E_Qty>
</E_Record>
<E_Record>
<Rec_Type>E</Rec_Type>
<E_Qty>2</E_Qty>
</E_Record>
</L_Record>
<L_Record>
<Rec_Type>L</Rec_Type>
<L_Level>2</L_Level>
<E_Record>
<Rec_Type>E</Rec_Type>
<E_Qty>5</E_Qty>
</E_Record>
<E_Record>
<Rec_Type>E</Rec_Type>
<E_Qty>6</E_Qty>
</E_Record>
</L_Record>
<R_Record>
<Rec_Type>R</Rec_Type>
</R_Record>
</Record>
I have written the XSLT mapping for this as below but i am not getting the required output. Could you please help me on this?
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Record/L_Record">
<L_Record>
<xsl:variable name="header" select="."/>
<xsl:apply-templates/>
<xsl:if test = "not(following-sibling::L_Record)">
<xsl:for-each select="following-sibling::E_Record[preceding-sibling::L_Record = $header]">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:if>
</L_Record>
</xsl:template>
</xsl:stylesheet>
Please help me on this?
When i am executing the above code, Record 1 is working fine, but the record 2 is not working properly. The E-Record segment is not appearing in the L-Record segment.
Upvotes: 0
Views: 97
Reputation: 52888
You should be able to create an xsl:key matching E_Record
elements and use the generated id of the first preceding L_Record
sibling as the key.
Then you can match L_Record
elements and copy the node set with the matching key.
Example...
<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="e_recs" match="E_Record" use="generate-id(preceding-sibling::L_Record[1])"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="L_Record">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<xsl:copy-of select="key('e_recs',generate-id())"/>
</xsl:copy>
</xsl:template>
<xsl:template match="E_Record"/>
</xsl:stylesheet>
Fiddle: http://xsltfiddle.liberty-development.net/94Acsmd
Upvotes: 0
Reputation: 239
Hi Please test this code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="L_Record">
<xsl:copy>
<xsl:apply-templates/>
<xsl:if test="following-sibling::*[1][self::E_Record]">
<xsl:call-template name="Next_E_Record">
<xsl:with-param name="next" select="following-sibling::*[1][self::E_Record]"></xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:copy>
</xsl:template>
<xsl:template name="Next_E_Record">
<xsl:param name="next"/>
<xsl:copy-of select="$next"/>
<xsl:if test="$next/following-sibling::*[1][self::E_Record]">
<xsl:call-template name="Next_E_Record">
<xsl:with-param name="next" select="$next/following-sibling::*[1][self::E_Record]"></xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="E_Record"/>
</xsl:stylesheet>
See Transformation at https://xsltfiddle.liberty-development.net/bFWRApe
Upvotes: 2
Reputation: 335
One way would be to loop through the children of record
until you find an L_Record
then add siblings until you find another L_Record
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Record">
<Record>
<xsl:for-each select='*'>
<xsl:choose>
<xsl:when test='name()="E_Record"'/>
<xsl:when test='name()="L_Record"'>
<L_Record>
<xsl:copy-of select="*"/>
<xsl:call-template name='next'>
<xsl:with-param name='current_L' select='.'/>
<xsl:with-param name='remainder' select='following-sibling::*'/>
</xsl:call-template>
</L_Record>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</Record>
</xsl:template>
<xsl:template name='next'>
<xsl:param name='current_L'/>
<xsl:param name='remainder'/>
<xsl:param name='first' select='$remainder[1]'/>
<xsl:if test='$remainder and not(name($first)="L_Record")'>
<xsl:copy-of select="$first"/>
<xsl:call-template name='next'>
<xsl:with-param name='current_L' select='$current_L'/>
<xsl:with-param name='remainder' select='$remainder[position() > 1]'/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0