链接节点集的预转换(首先对子节点进行排序,然后对排序结果进行另一个转换)。我的代码可以简化吗?

chaining pre-transformations for a node-set (first sorting child nodes, then another transformation on the sorted result). Can my code be simplified?

我正在使用 xsl:copy 进行一系列连续的(预)转换。首先,对子元素进行排序,然后对排序结果进行预转换。 (之后可以链接更多预转换)。

问题是我也在使用 node-set()。 我的解决方案有效,但对每个预转换都使用身份转换,这似乎是错误的。

来源

<albums>
    <album title="hits of the 90s" status="ready">
        <tracks>
            <track id="01" year="1992" title="I'm Too Sexy" />
            <track id="02" year="1991" title="Baby Baby" />
            <track id="03" year="1990" title="It Must Have Been Love" />
            <track id="04" year="1994" title="Here Comes the Hotstepper" />
            <track id="05" year="1998" title="Gettin' Jiggy Wit It" />
            <track id="06" year="1993" title="Dreamlover" />
            <track id="07" year="1996" title="Macarena"/>
            <track id="08" year="1995" title="Gangsta's Paradise" />
            <track id="09" year="1996" title="Un-Break My Heart" />
            <track id="10" year="1997" title="Wannabe" />
            <track id="11" year="1999" title="Baby One More Time" />
            <track id="12" year="1998" title="My Heart Will Go On"/>
        </tracks>
    </album>
</albums>

输出

<album title="hits of the 90s" status="ready">
    <tracks>
        <sideA>
            <track id="03" year="1990" title="It Must Have Been Love"/>
            <track id="02" year="1991" title="Baby Baby"/>
            <track id="01" year="1992" title="I'm Too Sexy"/>
            <track id="06" year="1993" title="Dreamlover"/>
            <track id="04" year="1994" title="Here Comes the Hotstepper"/>
            <track id="08" year="1995" title="Gangsta's Paradise"/>
        </sideA>
        <sideB>
            <track id="07" year="1996" title="Macarena"/>
            <track id="09" year="1996" title="Un-Break My Heart"/>
            <track id="10" year="1997" title="Wannabe"/>
            <track id="05" year="1998" title="Gettin' Jiggy Wit It"/>
            <track id="12" year="1998" title="My Heart Will Go On"/>
            <track id="11" year="1999" title="Baby One More Time"/>
        </sideB>
    </tracks>
</album>

代码

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" xmlns:msxsl="urn:schemas-microsoft-com:xslt" extension-element-prefixes="exsl msxsl">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>

    <xsl:template match="/">
        <xsl:variable name="vAlbums">
            <xsl:apply-templates select="albums/album[@status = 'ready']" mode="chained_subtransformations">
                <xsl:sort select="@title" data-type="text" order="ascending"/>
            </xsl:apply-templates>
        </xsl:variable>
        <xsl:copy-of select="msxsl:node-set($vAlbums)"/>
    </xsl:template>

    <xsl:template match="album" mode="chained_subtransformations">
        <xsl:if test="tracks/track">
            <!-- sort the tracks -->
            <xsl:variable name="album_with_sorted_tracks">
                <xsl:apply-templates select="." mode="sorttracks"/>
            </xsl:variable>
            <!-- split the album in half -->
            <xsl:variable name="splitAlbum">
                <xsl:apply-templates select="msxsl:node-set($album_with_sorted_tracks)" mode="split"/>
            </xsl:variable>
            <!-- the following line could be replaced with the apply-templates of the previous subtransformation -->
            <xsl:copy-of select="msxsl:node-set($splitAlbum)"/>
        </xsl:if>
    </xsl:template>

    <!-- SORTING THE TRACKS -->
    <xsl:template match="node() | @*" mode="sorttracks">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*" mode="sorttracks"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="tracks" mode="sorttracks">
        <tracks>
            <xsl:for-each select="track">
                <xsl:sort select="@year" data-type="number"/>
                <xsl:copy-of select="."/>
            </xsl:for-each>
        </tracks>
    </xsl:template>

    <!-- SPLITTING THE ALBUM -->
    <xsl:template match="node() | @*" mode="split">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*" mode="split"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="tracks" mode="split">
        <xsl:variable name="halfOfTotalTracks" select="floor(count(track) div 2)"/>
        <tracks>
            <sideA>
                <xsl:for-each select="track[position() &lt;= $halfOfTotalTracks]">
                    <xsl:sort select="@year" data-type="number"/>
                    <xsl:copy-of select="."/>
                </xsl:for-each>
            </sideA>
            <sideB>
                <xsl:for-each select="track[position() &gt; $halfOfTotalTracks]">
                    <xsl:sort select="@year" data-type="number"/>
                    <xsl:copy-of select="."/>
                </xsl:for-each>
            </sideB>
        </tracks>
    </xsl:template>
</xsl:stylesheet>

xslt1.0,处理器:MSXML3

我不确定您所说的“预转换”和尤其是什么意思。通过这个:

more pre-transformations could be chained afterwards

AFAICT,你可以这样做:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
extension-element-prefixes="msxsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="/albums">
    <xsl:apply-templates select="album[@status = 'ready']">
        <xsl:sort select="@title" data-type="text" order="ascending"/>
    </xsl:apply-templates>
</xsl:template>
    
<xsl:template match="album">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:variable name="track-count" select="count(tracks/track)" />
        <xsl:if test="$track-count">
            <xsl:variable name="sorted-tracks-RTF">
                <xsl:for-each select="tracks/track">
                    <xsl:sort select="@year" data-type="number" order="ascending"/>
                    <xsl:copy-of select="."/>
                </xsl:for-each>
            </xsl:variable> 
            <xsl:variable name="sorted-tracks" select="msxsl:node-set($sorted-tracks-RTF)/track"/>
            <tracks>
                <sideA>
                    <xsl:apply-templates select="$sorted-tracks[position() &lt;= $track-count div 2]"/>
                </sideA>
                <sideB>
                    <xsl:apply-templates select="$sorted-tracks[position() > $track-count div 2]"/>
                </sideB>            
            </tracks>
        </xsl:if>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

此结构允许您添加更多模板以在将任何节点发送到输出之前进一步转换它。在没有这样的覆盖模板的情况下,所有节点都由 identity transform 模板处理,该模板复制它们 原样

如果您不需要额外的处理,那么您可以直接将节点复制到输出并摆脱 identity transform 模板。