在 XSLT 1.0 中根据批量大小输出新行

Outputting a new row based on batch size in XSLT 1.0

我正在使用 xslt 将 xml 转换为竖线分隔文件,xslt 版本 1.0。一个人可以有很多类。我正在努力弄清楚如何在 1.0 版中以 5 类 为一组创建新行?

示例代码片段

<root>
    <Person>
        <Name>Doug</Name>
        <Class>
            <ClassID>AS</ClassID>
        </Class>
        <Class>
            <ClassID>BA</ClassID>
        </Class>
        <Class>
            <ClassID>ZX</ClassID>
        </Class>
        <Class>
            <ClassID>MSN</ClassID>
        </Class>
        <Class>
            <ClassID>ABSN</ClassID>
        </Class>
        <Class>
            <ClassID>FS</ClassID>
        </Class>
    </Person>

    <Person>
        <Name>Amy</Name>
        <Class>
            <ClassID>AS</ClassID>
        </Class>
        <Class>
            <ClassID>BA</ClassID>
        </Class>
    </Person>
    
    <Person>
        <Name>Charlotte</Name>
        <Class>
            <ClassID>BA</ClassID>
        </Class>
    </Person>
    
    <Person>
        <Name>Betty</Name>
        <Class>
            <ClassID>ZX</ClassID>
        </Class>
    </Person>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>

    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>
    <xsl:variable name="linefeed" select="'&#xA;'"/>
    

    <xsl:template match="/">

        <File>
            <Body>
                <xsl:apply-templates select="root/Person"/>
            </Body>
        </File>
    </xsl:template>

    <xsl:template match="root/Person">
            <xsl:value-of select="Name"/>
        
            <xsl:for-each select="Class">
                <xsl:text>|</xsl:text>
                <xsl:value-of select="ClassID" />
            </xsl:for-each>
            <xsl:value-of select="$linefeed"/>
    </xsl:template>


    </xsl:stylesheet>

而不是这个

Doug|AS|BA|ZX|MSN|ABSN|FS
Amy|AS|BA
Charlotte|BA
Betty|ZX

我需要这个 - 道格现在有两行,因为他有超过 5 类(只有 5 类 可以放在一行上)。这需要是动态的,可能有 100 类.

Doug|AS|BA|ZX|MSN|ABSN
Doug|FS
Amy|AS|BA
Charlotte|BA
Betty|ZX

我一直在兜圈子-请帮忙!

您可以使用这样的递归模板来完成:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>

    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>
    <xsl:variable name="linefeed" select="'&#xA;'"/>
    

    <xsl:template match="/">
        <xsl:apply-templates select="root/Person"/>
    </xsl:template>

    <xsl:template match="Person">
        <xsl:call-template name="PersonOutput">
            <xsl:with-param name="index" select="1"/>
            <xsl:with-param name="person" select="."/>
        </xsl:call-template>
    </xsl:template>
    
    <xsl:template name="PersonOutput">
        <xsl:param name="index"/>
        <xsl:param name="person"/>
        <xsl:if test="$index=1 or ($index mod 5)=1">
            <xsl:value-of select="$linefeed"/>
            <xsl:value-of select="$person/Name"/>
        </xsl:if>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="$person/Class[$index]/ClassID"/>
        
        <xsl:if test="$person/Class[$index]/following-sibling::Class">
            <xsl:call-template name="PersonOutput">
                <xsl:with-param name="index" select="$index+1"/>
                <xsl:with-param name="person" select="$person"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

看到它在这里工作:https://xsltfiddle.liberty-development.net/3Mvnt4c

这里有一个相当简单的查看方式:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:template match="/root">
    <xsl:for-each select="Person">
        <xsl:variable name="name" select="Name" />
        <xsl:for-each select="Class[position() mod 5 = 1]" >
            <xsl:value-of select="$name" />
            <xsl:for-each select=". | following-sibling::Class[position() &lt; 5]">
                <xsl:text>|</xsl:text>
                <xsl:value-of select="ClassID" />
            </xsl:for-each>
            <xsl:text>&#10;</xsl:text>
        </xsl:for-each>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>