Xslt 分组XML元素

Xslt 分组XML元素,xslt,xslt-2.0,Xslt,Xslt 2.0,我正在尝试对以下XML进行分组: <?xml version="1.0" encoding="UTF-8"?> <EDIFACT segmentDelimiter="&#39;" itemDelimiter="+" elementDelimiter=":" decimalCharacter="." escapeCharacter="?"> <Envelope count='1'> <UNB>

我正在尝试对以下XML进行分组:

<?xml version="1.0" encoding="UTF-8"?>
<EDIFACT segmentDelimiter="&#39;" itemDelimiter="+" elementDelimiter=":" decimalCharacter="." escapeCharacter="?">
    <Envelope count='1'>
        <UNB>
            <I1>
                <E1>UNOA</E1>
                <E2>2</E2>
            </I1>
        </UNB>
        <Message count='1'>
            <UNH>
                <I1>
                    <E1>8351519</E1>
                </I1>
                <I2>
                    <E1>MESTYP</E1>
                    <E2>D</E2>
                    <E3>96A</E3>
                    <E4>UN</E4>
                </I2>
            </UNH>
            <BGM>
                <I1>
                    <E1>351</E1>
                </I1>
                <I2>
                    <E1>8351519</E1>
                </I2>
            </BGM>
            <DTM>
                <I1>
                    <E1>137</E1>
                    <E2>20130429</E2>
                    <E3>102</E3>
                </I1>
            </DTM>
            <DTM>
                <I1>
                    <E1>132</E1>
                    <E2>20130521</E2>
                    <E3>102</E3>
                </I1>
            </DTM>
            <CPS>
                <I1>
                    <E1>1</E1>
                </I1>
            </CPS>
            <LIN>
                <I1>
                    <E1/>
                </I1>
                <I2>
                    <E1/>
                </I2>
                <I3>
                    <E1>859700015000</E1>
                </I3>
            </LIN>
            <QTY>
                <I1>
                    <E1>12</E1>
                    <E2>305</E2>
                </I1>
            </QTY>
            <SGP>
                <I1>
                    <E1>KA02</E1>
                    <E2>129</E2>
                </I1>
            </SGP>
            <SGP>
                <I1>
                    <E1>0001</E1>
                    <E2>156</E2>
                </I1>
            </SGP>
            <SGP>
                <I1>
                    <E1>1ST CHOICE</E1>
                    <E2>189</E2>
                </I1>
            </SGP>
            <CPS>
                <I1>
                    <E1>2</E1>
                </I1>
            </CPS>
            <LIN>
                <I1>
                    <E1/>
                </I1>
                <I2>
                    <E1/>
                </I2>
                <I3>
                    <E1>859700015010</E1>
                </I3>
            </LIN>
            <QTY>
                <I1>
                    <E1>12</E1>
                    <E2>424</E2>
                </I1>
            </QTY>
            <SGP>
                <I1>
                    <E1>KA02</E1>
                    <E2>129</E2>
                </I1>
            </SGP>
            <SGP>
                <I1>
                    <E1>0001</E1>
                    <E2>156</E2>
                </I1>
            </SGP>
            <SGP>
                <I1>
                    <E1>1ST CHOICE</E1>
                    <E2>189</E2>
                </I1>
            </SGP>
            <UNT>
                <I1>
                    <E1>89</E1>
                </I1>
                <I2>
                    <E1>8351519</E1>
                </I2>
            </UNT>
        </Message>
        <UNZ>
            <I1>
                <E1>1</E1>
            </I1>
            <I2>
                <E1>8351519</E1>
            </I2>
        </UNZ>
    </Envelope>
</EDIFACT>

这几乎是正确的。我只遗漏了结果中的第一个
CPS
元素。

当使用以开头的
组时,为了避免包装不属于组的元素,我建议使用

<xsl:template match="Message">
    <!-- Copy 'Message' node itself -->
    <xsl:copy>
        <!-- Also copy attributes of 'Message' node -->
        <xsl:apply-templates select="@*" />

        <!-- Group by CPS nodes -->
        <xsl:for-each-group select="*" group-starting-with="CPS">
            <!-- Before any CPS node, put a articleLine node (UNH gets included also at this moment and UNT) -->
            <xsl:choose>
              <xsl:when test="self::CPS">
                <articleLine>
                    <xsl:apply-templates select="current-group()" />
                </articleLine>
              </xsl:when>
              <xsl:otherwise>
                <xsl:apply-templates select="current-group()"/>
              </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="fn xs">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <!-- Identity template (copies all nodes and attributes) -->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" />
        </xsl:copy>
    </xsl:template>

        <!-- When 'Message' node is found, do following -->
    <xsl:template match="Message">
        <!-- Copy 'Message' node itself -->
        <xsl:copy>
            <!-- Also copy attributes of 'Message' node -->
            <xsl:apply-templates select="@*" />

            <!-- Group by CPS nodes -->
            <xsl:for-each-group select="*" group-starting-with="CPS">
                <!-- Before any CPS node, put a articleLine node (UNH gets included also at this moment and UNT) -->
                <articleLine>
                    <xsl:apply-templates select="current-group()" />
                </articleLine>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
<!-- When 'Message' node is found, do following -->
<xsl:template match="Message">
    <!-- Copy 'Message' node itself -->
    <xsl:copy>
        <!-- Also copy attributes of 'Message' node -->
        <xsl:apply-templates select="@*" />

        <!--xsl:copy-of select="UNH|BGM|DTM" / -->
        <xsl:copy-of select="CPS[1]/preceding-sibling::*" />

        <!-- Group by CPS nodes -->
        <xsl:for-each-group select="CPS[1]/following-sibling::*[name()!='UNT']" group-starting-with="CPS">
            <!-- Before any CPS node, put a articleLine node (UNH gets included also at this moment) -->
            <articleLine>
                <xsl:apply-templates select="current-group()" />
            </articleLine>
        </xsl:for-each-group>

        <xsl:copy-of select="UNT" />
    </xsl:copy>
</xsl:template>
<xsl:template match="Message">
    <!-- Copy 'Message' node itself -->
    <xsl:copy>
        <!-- Also copy attributes of 'Message' node -->
        <xsl:apply-templates select="@*" />

        <!-- Group by CPS nodes -->
        <xsl:for-each-group select="*" group-starting-with="CPS">
            <!-- Before any CPS node, put a articleLine node (UNH gets included also at this moment and UNT) -->
            <xsl:choose>
              <xsl:when test="self::CPS">
                <articleLine>
                    <xsl:apply-templates select="current-group()" />
                </articleLine>
              </xsl:when>
              <xsl:otherwise>
                <xsl:apply-templates select="current-group()"/>
              </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="fn xs">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <!-- Identity template (copies all nodes and attributes) -->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" />
        </xsl:copy>
    </xsl:template>

        <!-- When 'Message' node is found, do following -->
    <xsl:template match="Message">
        <!-- Copy 'Message' node itself -->
        <xsl:copy>
            <!-- Also copy attributes of 'Message' node -->
            <xsl:apply-templates select="@*" />

            <!-- Group by CPS nodes -->
            <xsl:for-each-group select="* except UNT" group-starting-with="CPS">
                <!-- Before any CPS node, put a articleLine node (UNH gets included also at this moment and UNT) -->
                <xsl:choose>
                  <xsl:when test="self::CPS">
                    <articleLine>
                        <xsl:apply-templates select="current-group()" />
                    </articleLine>
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:apply-templates select="current-group()"/>
                  </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>

            <xsl:apply-templates select="UNT"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>