xslt-2.0xslt-3.0

XSLT Selecting last position under segment


my requirement is to consider last GS15 occurrence under HEADER/GS9 by removing other GS15 in it, if GS9 has only one GS15 occurrence or no GS15 then we can copy the GS9 segment as it is. If there is no GS9 in the input, we need to have rest of the data. my xslt is working if only one GS9 exist under HEADER. for multiple GS9 segments its giving me sequence error, Please have a look once.

Input:

<?xml version="1.0" encoding="UTF-8"?>
<HEADER>
    <SUBNODE>
        <FIELD1>001</FIELD1>
    </SUBNODE>
    <GS1>
        <FIELD1>12</FIELD1>
    </GS1>
    <GS9>
        <SUBN>
            <FIELD1>1</FIELD1>
        </SUBN>
        <GS11>
            <FIELD1>12</FIELD1>
        </GS11>
        <GS15>
            <GS16>
                <ATC>
                    <FIELD1>HE</FIELD1>
                </ATC>
            </GS16>
        </GS15>
        <GS15>
            <GS16>
                <ATC>
                    <FIELD1>123</FIELD1>
                </ATC>
            </GS16>
        </GS15>
    </GS9>
    <GS9>
        <SUBN>
            <FIELD1>1</FIELD1>
        </SUBN>
        <GS11>
            <FIELD1>12</FIELD1>
        </GS11>
        <GS15>
            <GS16>
                <ATC>
                    <FIELD1>245</FIELD1>
                </ATC>
            </GS16>
        </GS15>
        <GS15>
            <GS16>
                <ATC>
                    <FIELD1>456</FIELD1>
                </ATC>
            </GS16>
        </GS15>
    </GS9>
    <GS9>
        <SUBN>
            <FIELD1>1</FIELD1>
        </SUBN>
        <GS11>
            <FIELD1>12</FIELD1>
        </GS11>
    </GS9>
    <GS18>
        <FIELD1>4141</FIELD1>
    </GS18>
</HEADER>


Desired output:

<?xml version="1.0" encoding="UTF-8"?>
<HEADER>
    <SUBNODE>
        <FIELD1>001</FIELD1>
    </SUBNODE>
    <GS1>
        <FIELD1>12</FIELD1>
    </GS1>
    <GS9>
        <SUBN>
            <FIELD1>1</FIELD1>
        </SUBN>
        <GS11>
            <FIELD1>12</FIELD1>
        </GS11>
        <GS15>
            <GS16>
                <ATC>
                    <FIELD1>123</FIELD1>
                </ATC>
            </GS16>
        </GS15>
    </GS9>
    <GS9>
        <SUBN>
            <FIELD1>1</FIELD1>
        </SUBN>
        <GS11>
            <FIELD1>12</FIELD1>
        </GS11>
        <GS15>
            <GS16>
                <ATC>
                    <FIELD1>456</FIELD1>
                </ATC>
            </GS16>
        </GS15>
    </GS9>
    <GS9>
        <SUBN>
            <FIELD1>1</FIELD1>
        </SUBN>
        <GS11>
            <FIELD1>12</FIELD1>
        </GS11>
    </GS9>
    <GS18>
        <FIELD1>4141</FIELD1>
    </GS18>
</HEADER>

XSLT I used is below:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:key name="gs15key" match="GS15" use="generate-id()"/>
    <xsl:template match="/HEADER">
        <HEADER>
            <xsl:apply-templates select="node()"/>
        </HEADER>
    </xsl:template>
    <xsl:template match="GS15">
        <xsl:if test="generate-id() = generate-id(//GS15[last()])">
            <G_SG15>
                <xsl:apply-templates select="node()"/>
            </G_SG15>
        </xsl:if>
    </xsl:template>
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

 
   
        

Solution

  • Use an empty template for any non last GS15 child element of a GS9 parent plus the identity transformation

      <xsl:template match="GS9/GS15[position() != last()]"/>
    
      <xsl:mode on-no-match="shallow-copy"/>