XSLT - 如何在新的父节点中对一组递归节点进行分组

XSLT - How grouping a set of recursive nodes within a new parent node

我开始使用 XSLT,在探索了一些解决方案之后,我认为与您分享我的问题是个好主意。也许有人可以帮我解决这个问题。

我有一个 XML 这样的输入数据:

<?xml version="1.0" encoding="windows-1252"?>
<DOCUMENT>
<SSDP>
    <DP>A</DP>
    <DX>B</DX>
    <XN>1</XN>
    <PP>2</PP>
    <CO>3</CO>
    <XN>4</XN>
    <PP>5</PP>
    <XN>6</XN>
    <PP>7</PP>
    <CO>8</CO>
</SSDP>
<SSDP>
    <DP>A</DP>
    <DL>B</DL>
    <DX>C</DX>
    <XN>1</XN>
    <PP>2</PP>
    <CO>3</CO>
    <XN>4</XN>
    <PP>5</PP>
</SSDP>
</DOCUMENT>

如你所见,有一组递归节点。具体来说,每个“XN”节点开始一组新的递归节点,直到下一个“XN”字段。 (“XN”节点之间的字段数可以是动态的,如您在输入 XML 示例中所见)。挑战是在新节点“DATA”中包含每组递归节点。

想要的输出如下:

<?xml version="1.0" encoding="windows-1252"?>
<DOCUMENT>
<SSDP>
    <DP>A</DP>
    <DX>B</DX>
    <DATA>
        <XN>1</XN>
        <PP>2</PP>
        <CO>3</CO>
    </DATA>
    <DATA>
        <XN>4</XN>
        <PP>5</PP>
    </DATA>
    <DATA>
        <XN>6</XN>
        <PP>7</PP>
        <CO>8</CO>
    </DATA>
</SSDP>
<SSDP>
    <DP>A</DP>
    <DL>B</DL>
    <DX>C</DX>
    <DATA>
        <XN>1</XN>
        <PP>2</PP>
        <CO>3</CO>
    </DATA>
    <DATA>
        <XN>4</XN>
        <PP>5</PP>
    </DATA>
</SSDP>
</DOCUMENT>

正如我之前所说,我是 XSLT 的初学者,我试图创建一个来解决这个问题,但恐怕我还没有足够的知识。

我的第一个 XSLT 版本如下:

<?xml version="1.0" encoding="windows-1252"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:template match="DOCUMENT">
        <DOCUMENT>
        <xsl:for-each select="SSDP">
            <SSDP>
            <xsl:for-each select="*">
                <!-- First element that define a DATA node -->
                <xsl:if test="name(.)='XN'">
                    <xsl:element name="DATA">                   
                        <xsl:copy-of select="."/>
                    </xsl:element>
                </xsl:if>
                <!-- List of elements that define a DATA node -->
                <xsl:if test="name(.)!='XN' and
                              name(.)!='PP' and
                              name(.)!='CO'">
                    <xsl:copy-of select="."/>
                </xsl:if>
            </xsl:for-each>
            </SSDP>
        </xsl:for-each>
        </DOCUMENT>
    </xsl:template>
</xsl:stylesheet>

但结果不完整...

<?xml version="1.0" encoding="UTF-8"?>
<DOCUMENT>
   <SSDP>
      <DP>A</DP>
      <DX>B</DX>
      <DATA>
         <XN>1</XN>
      </DATA>
      <DATA>
         <XN>4</XN>
      </DATA>
      <DATA>
         <XN>6</XN>
      </DATA>
   </SSDP>
   <SSDP>
      <DP>A</DP>
      <DL>B</DL>
      <DX>C</DX>
      <DATA>
         <XN>1</XN>
      </DATA>
      <DATA>
         <XN>4</XN>
      </DATA>
   </SSDP>
</DOCUMENT>

我想在包含“DATA”节点并将鼠标悬停在“XN”节点上之后,我需要添加以下“PP”或“CO”节点,使用诸如“following::”之类的函数。 ..但我不知道如何。

另外,恐怕有比我想象的更好的方法来解决这个问题。

提前致谢!

Also I'm afraid that there is a much better way to resolve this issue than I'm thinking.

我相信有:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:template match="/DOCUMENT">
    <xsl:copy>
        <xsl:for-each select="SSDP">
            <xsl:copy>
                <xsl:for-each-group select="*" group-starting-with="XN">
                    <xsl:choose>
                        <xsl:when test="self::XN">
                            <DATA>
                                <xsl:copy-of select="current-group()" />
                            </DATA>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:copy-of select="current-group()" />
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:for-each-group>
            </xsl:copy>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>