Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Grouping and Maintain the Sequence

My current requirement is to group K18 based on ALF,OND, then K18 corresponding P04Y,P04Z,P04,P03 must be grouped in sequence as it is predefined structure of K18, but all are optional segments including K18. If any segment not exist then we can ignore that.

XSLT i used is placing the grouped values after last segment, how can i group them in sequence mentioned. if i use sort function then its giving me P03,P04,P04Y and P04Z.

Input:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

<?xml version="1.0" encoding="UTF-8"?>
<ROOT>
    <LEAV ONE="1">
        <EDI SEGMENT="1">
            <FIELD1>EDI</FIELD1>
        </EDI>
        <AK1 SEGMENT="1">
            <VW>RS</VW>
        </AK1>
        <K18 SEGMENT="1">
            <ALF>001</ALF>
            <OND>ACF</OND>
            <P04Y SEGMENT="1">
                <K_1>VALUE1</K_1>
            </P04Y>
            <P04Z SEGMENT="1">
                <REGN>HU</REGN>
            </P04Z>
            <P04 SEGMENT="1">
                <B_DOC>810</B_DOC>
            </P04>
            <P03 SEGMENT="1">
                <FIELD1>X</FIELD1>
                <SEQ>10</SEQ>
                <RNTAM>VALUE1</RNTAM>
            </P03>      
        </K18>
        <K18 SEGMENT="1">
            <ALF>001</ALF>
            <OND>ACF</OND>
            <P04Y SEGMENT="1">
                <K_1>VALUE1</K_1>
            </P04Y>
            <P04Z SEGMENT="1">
                <REGN>HU</REGN>
            </P04Z>
            <P04 SEGMENT="1">
                <B_DOC>810</B_DOC>
            </P04>
            <P03 SEGMENT="1">
                <FIELD1>X</FIELD1>
                <SEQ>20</SEQ>
                <RNTAM>VALUE2</RNTAM>
            </P03>
        </K18>
        <K18 SEGMENT="1">
            <ALF>001</ALF>
            <OND>ACF</OND>
            <P04Y SEGMENT="1">
                <K_1>new value</K_1>
            </P04Y>
            <P04Z SEGMENT="1">
                <REGN>new</REGN>
            </P04Z>         
            <P03 SEGMENT="1">
                <FIELD1>X</FIELD1>
                <SEQ>30</SEQ>
                <RNTAM>VALUE2</RNTAM>
            </P03>
        </K18>
        <K18 SEGMENT="1">
            <ALF>001</ALF>
            <OND>FCB</OND>      
        </K18>
        <K28 SEGMENT="1">
            <BCOUN>ES</BCOUN>
        </K28>
        <P01 SEGMENT="1">
            <FIELD1>10</FIELD1>
            <FIELD2>1</FIELD2>    
        </P01>
        <P01 SEGMENT="1">
            <FIELD1>10</FIELD1>
            <FIELD2>1</FIELD2>
            <P02 SEGMENT="1">
                <FIELD1>001</FIELD1>
            </P02>
        </P01>        
        <PS01 SEGMENT="1">
            <FIELD1>VALUE</FIELD1>
        </PS01>
    </LEAV>
</ROOT>

** Desired Output:**

<?xml version="1.0" encoding="UTF-8"?>
<ROOT>
    <LEAV ONE="1">
        <EDI SEGMENT="1">
            <FIELD1>EDI</FIELD1>
        </EDI>
        <AK1 SEGMENT="1">
            <VW>RS</VW>
        </AK1>
        <K18 SEGMENT="1">
            <ALF>001</ALF>
            <OND>ACF</OND>
            <P04Y SEGMENT="1">
                <K_1>VALUE1</K_1>
            </P04Y>
            <P04Y SEGMENT="1">
                <K_1>new value</K_1>
            </P04Y>
            <P04Z SEGMENT="1">
                <REGN>HU</REGN>
            </P04Z>
            <P04Z SEGMENT="1">
                <REGN>new</REGN>
            </P04Z>
            <P04 SEGMENT="1">
                <B_DOC>810</B_DOC>
            </P04>          
            <P03 SEGMENT="1">
                <FIELD1>X</FIELD1>
                <SEQ>10</SEQ>
                <RNTAM>VALUE1</RNTAM>
            </P03>
            <P03 SEGMENT="1">
                <FIELD1>X</FIELD1>
                <SEQ>20</SEQ>
                <RNTAM>VALUE2</RNTAM>
            </P03>
            <P03 SEGMENT="1">
                <FIELD1>X</FIELD1>
                <SEQ>30</SEQ>
                <RNTAM>VALUE2</RNTAM>
            </P03>
        </K18>
        <K18 SEGMENT="1">
            <ALF>001</ALF>
            <OND>FCB</OND>      
        </K18>
        <K28 SEGMENT="1">
            <BCOUN>ES</BCOUN>
        </K28>
        <P01 SEGMENT="1">
            <FIELD1>10</FIELD1>
            <FIELD2>1</FIELD2>
            <P02 SEGMENT="1">
                <FIELD1>001</FIELD1>
            </P02>
            <TP1 SEGMENT="1">
                <ID>01</ID>
                <RAS>X</RAS>
                <PT2 SEGMENT="1">
                    <LINE>VALUE1</LINE>
                </PT2>
                <PT2 SEGMENT="1">
                    <LINE>VALUE2</LINE>
                </PT2>          
            </TP1>
        </P01>
        <P01 SEGMENT="1">
            <FIELD1>10</FIELD1>
            <FIELD2>1</FIELD2>
            <P02 SEGMENT="1">
                <FIELD1>001</FIELD1>
            </P02>
        </P01>
        <P01 SEGMENT="1">
            <FIELD1>10</FIELD1>
            <FIELD2>1</FIELD2>
            <P02 SEGMENT="1">
                <FIELD1>001</FIELD1>
            </P02>
            <TP1 SEGMENT="1">
                <ID>01</ID>
                <RAS>X</RAS>
                <PT2 SEGMENT="1">
                    <LINE>VALUE1</LINE>
                </PT2>
            </TP1>
            <TP1 SEGMENT="1">
                <ID>02</ID>
                <RAS>X</RAS>
                <PT2 SEGMENT="1">
                    <LINE>VALUE2</LINE>
                </PT2>
            </TP1>
        </P01>
        <PS01 SEGMENT="1">
            <FIELD1>VALUE</FIELD1>
        </PS01>
    </LEAV>
</ROOT>

** XSLT I used is below:**

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" expand-text="yes">
    <xsl:template match="LEAV">
        <xsl:copy>
            <xsl:apply-templates select="@*, if (K18) then (* except (K18/(., following-sibling::*))) else *"/>
            <xsl:for-each-group select="K18" composite="yes" group-by="ALF, OND">
                <xsl:copy>
                    <xsl:apply-templates select="@*, ALF, OND"/>
                    <xsl:for-each-group select="current-group()!* except (current-group()!(ALF, OND))" composite="yes" group-by="node-name(), @*, *">
                        <xsl:sequence select="."/>
                    </xsl:for-each-group>
                </xsl:copy>
            </xsl:for-each-group>
            <xsl:apply-templates select="K18/following-sibling::*[not(self::K18)]"/>
            <xsl:apply-templates select="if (K18) then (* except (K18/(., preceding-sibling::*))) else ()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:output method="xml" indent="yes"/>
    <xsl:mode on-no-match="shallow-copy"/>
</xsl:stylesheet>

>Solution :

Use an xsl:sort based on the original position stored in an accumulator:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" expand-text="yes">
    
    <xsl:accumulator name="K18-child-pos" as="xs:integer?" initial-value="()">
      <xsl:accumulator-rule match="K18" select="0"/>
      <xsl:accumulator-rule match="K18/*" select="$value + 1"/>
    </xsl:accumulator>
    
    <xsl:template match="LEAV">
        <xsl:copy>
            <xsl:apply-templates select="@*, if (K18) then (* except (K18/(., following-sibling::*))) else *"/>
            <xsl:for-each-group select="K18" composite="yes" group-by="ALF, OND">
                <xsl:copy>
                    <xsl:apply-templates select="@*, ALF, OND"/>
                    <xsl:for-each-group select="current-group()!* except (current-group()!(ALF, OND))" composite="yes" group-by="node-name(), @*, *">
                        <xsl:sort select="accumulator-before('K18-child-pos')"/>
                        <xsl:sequence select="."/>
                    </xsl:for-each-group>
                </xsl:copy>
            </xsl:for-each-group>
            <xsl:apply-templates select="K18/following-sibling::*[not(self::K18)]"/>
            <xsl:apply-templates select="if (K18) then (* except (K18/(., preceding-sibling::*))) else ()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:output method="xml" indent="yes"/>
    <xsl:mode on-no-match="shallow-copy" use-accumulators="K18-child-pos"/>
</xsl:stylesheet>
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading