i am trying to write XSLT mapping to move Segments to its corresponding header segment based on key field matches in (key field name ) and (key field name ) segments (MAT=IDEN), If key field not matches then no need to pass segment, i have written XSLT, but its not giving required transformation.
i attached sample input and output as below. Please check.
Input:
<?xml version="1.0" encoding="UTF-8"?>
<HEADER>
<CODI BEGIN="1">
<L20 SEGMENT="1">
<ELN>Value1</ELN>
<L24 SEGMENT="1">
<MAT>12345</MAT>
<field1>text </field1>
<ITEM SEGMENT="1">
<IDEN>12345</IDEN>
<Fields>00</Fields>
</ITEM>
<ITEM SEGMENT="1">
<IDEN>45678</IDEN>
<Fields>10</Fields>
</ITEM>
<ITEM SEGMENT="1">
<IDEN>45678</IDEN>
<Fields>11</Fields>
</ITEM>
<ITEM SEGMENT="1">
<IDEN>667788</IDEN>
<Fields>12</Fields>
</ITEM>
<ITEM SEGMENT="1">
<IDEN>667788</IDEN>
<Fields>13</Fields>
</ITEM>
<ITEM SEGMENT="1">
<IDEN>112233</IDEN>
<Fields>20</Fields>
</ITEM>
<L19 SEGMENT="1">
<LF>Value2</LF>
</L19>
</L24>
<L24 SEGMENT="1">
<MAT>45678</MAT>
<field1>text1 </field1>
<L19 SEGMENT="1">
<LF>Value2</LF>
</L19>
</L24>
<L24 SEGMENT="1">
<MAT>60987</MAT>
<field1>text2 </field1>
<L19 SEGMENT="1">
<LF>Value2</LF>
</L19>
</L24>
<L24 SEGMENT="1">
<MAT>667788</MAT>
<field1>text3 </field1>
<L19 SEGMENT="1">
<LF>Value2</LF>
</L19>
</L24>
<L24 SEGMENT="1">
<MAT>112233</MAT>
<field1>text4 </field1>
<L19 SEGMENT="1">
<LF>Value2</LF>
</L19>
</L24>
</L20>
</CODI>
</HEADER>
** Desired Output:**
<?xml version="1.0" encoding="UTF-8"?>
<HEADER>
<CODI BEGIN="1">
<L20 SEGMENT="1">
<ELN>Value1</ELN>
<L24 SEGMENT="1">
<MAT>12345</MAT>
<field1>text </field1>
<ITEM SEGMENT="1">
<IDEN>12345</IDEN>
<Fields>00</Fields>
</ITEM>
<L19 SEGMENT="1">
<LF>Value2</LF>
</L19>
</L24>
<L24 SEGMENT="1">
<MAT>45678</MAT>
<field1>text1 </field1>
<ITEM SEGMENT="1">
<IDEN>45678</IDEN>
<Fields>10</Fields>
</ITEM>
<ITEM SEGMENT="1">
<IDEN>45678</IDEN>
<Fields>11</Fields>
</ITEM>
<L19 SEGMENT="1">
<LF>Value2</LF>
</L19>
</L24>
<L24 SEGMENT="1">
<MAT>60987</MAT>
<field1>text2 </field1>
<L19 SEGMENT="1">
<LF>Value2</LF>
</L19>
</L24>
<L24 SEGMENT="1">
<MAT>667788</MAT>
<field1>text3 </field1>
<ITEM SEGMENT="1">
<IDEN>667788</IDEN>
<Fields>12</Fields>
</ITEM>
<ITEM SEGMENT="1">
<IDEN>667788</IDEN>
<Fields>13</Fields>
</ITEM>
<L19 SEGMENT="1">
<LF>Value2</LF>
</L19>
</L24>
<L24 SEGMENT="1">
<MAT>112233</MAT>
<field1>text4 </field1>
<ITEM SEGMENT="1">
<IDEN>112233</IDEN>
<Fields>20</Fields>
</ITEM>
<L19 SEGMENT="1">
<LF>Value2</LF>
</L19>
</L24>
</L20>
</CODI>
</HEADER>
** XSLT I used is below:**
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="IDEN-by-key" match="//ITEM" use="@IDEN" />
<!-- Identity template to copy all nodes as-is -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//L24">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
<xsl:for-each select="('IDEN-by-key', @IDEN)">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Please assist here.
As was indicated in the comments, for your xsl:key
you want to use the IDEN
element, not an @IDEN
attribute. Also, your XSLT was missing key()
when attempting to use it.
Since you want to replace all of the ITEM
and substitute with those that match the MAT
value, and place those ITEM
after the MAT
element in your output, I would suggest moving the copy of the ITEM
into a template for MAT
and creating an empty template for ITEM
. Additionally, you don't need to use an xsl:for-each
you can just xsl:copy-of and select from the
key(), and your match expressions don't need
//`:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="IDEN-by-key" match="ITEM" use="IDEN" />
<!-- Identity template to copy all nodes as-is -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="MAT">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<xsl:copy-of select="key('IDEN-by-key', .)"/>
</xsl:template>
<xsl:template match="ITEM"/>
</xsl:stylesheet>
Since you have updated the question and changed the inputs, if you want to ensure that the ITEM are produced before the L19 element, change which template you anchor to, but same concept:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="IDEN-by-key" match="ITEM" use="IDEN" />
<!-- Identity template to copy all nodes as-is -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ITEM"/>
<xsl:template match="L19" >
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<xsl:copy-of select="key('IDEN-by-key', ../MAT)"/>
</xsl:template>
</xsl:stylesheet>