在 XSLT 中为特定元素创建序列

Create a sequence for a specific element in XSLT

提问人:RamAlx 提问时间:11/17/2023 更新时间:11/18/2023 访问量:29

问:

我正在尝试创建一个按顺序将数字分配给 XML 元素的函数。让我举个例子。我想要的输出xml是这样的:

             <Item>
                <ZDoc>
                    <seq>1</seq>
                </ZDoc>
                <ZDoc>
                    <seq>2</seq>
                </ZDoc>
                <TDoc>
                    <seq>1</seq>
                </TDoc>
                <TDoc>
                    <seq>2</seq>
                </TDoc>
            </Item>
            <Item>
                <ZDoc>
                    <seq>1</seq>
                </ZDoc>
                <ZDoc>
                    <seq>2</seq>
                </ZDoc>
                <TDoc>
                    <seq>1</seq>
                </TDoc>
                <TDoc>
                    <seq>2</seq>
                </TDoc>
            </Item>

我创建了这个函数:

<xsl:template name="my_func()">
    <xsl:param name="id_name" select="''"/> 
    <!-- Count elements -->
    <xsl:variable name="seq" select="count(//*[local-name() = $global-id]) + 1"/>
    <!-- Output the generated sequence number -->
    <xsl:value-of select="$seq"/>
</xsl:template>

但它只返回序列号 1。此外,如您所见,id_name是节点名称,如 TDoc 和 ZDoc。 输出如下:

<Item>
                <ZDoc>
                    <seq>1</seq>
                </ZDoc>
                <ZDoc>
                    <seq>2</seq>
                </ZDoc>
                <TDoc>
                    <seq>1</seq>
                </TDoc>
                <TDoc>
                    <seq>1</seq>
                </TDoc>
            </Item>
            <Item>
                <ZDoc>
                    <seq>1</seq>
                </ZDoc>
                <ZDoc>
                    <seq>1</seq>
                </ZDoc>
                <TDoc>
                    <seq>1</seq>
                </TDoc>
                <TDoc>
                    <seq>1</seq>
                </TDoc>
            </Item>

我尝试了另一种似乎效果更好的方法,但它再次从最后一个元素中的 2 开始计数

<xsl:template name="my_func()">
    <xsl:param name="id" select="()"/>
    <xsl:variable name="auto_number" as="xs:integer" select="position() "/> 
    <xsl:sequence select="xs:integer($auto_number)"/>
</xsl:template>

但要知道输出是这样的:

<Item>
                <ZDoc>
                    <seq>1</seq>
                </ZDoc>
                <ZDoc>
                    <seq>2</seq>
                </ZDoc>
                <TDoc>
                    <seq>2</seq>
                </TDoc>
                <TDoc>
                    <seq>3</seq>
                </TDoc>
            </Item>
            <Item>
                <ZDoc>
                    <seq>1</seq>
                </ZDoc>
                <ZDoc>
                    <seq>2</seq>
                </ZDoc>
                <TDoc>
                    <seq>2</seq>
                </TDoc>
                <TDoc>
                    <seq>3</seq>
                </TDoc>
            </Item>
                                     

                                    <seq>                             
                                        <xsl:call-template 
                                             name="my_func">
                                            <xsl:with-param name="id" 
                                             select="'TDoc'" as="item()"/>
                                        </xsl:call-template>
                                    </seq>

我错过了什么??有什么想法吗??

XML XSLT-2.0

评论

0赞 Siebe Jongebloed 11/17/2023
请同时分享您的源 xml。
0赞 RamAlx 11/17/2023
这是我的源 XML @SiebeJongebloed
0赞 RamAlx 11/17/2023
啊对不起..我的源XML真的很大

答:

1赞 Daniel Haley 11/18/2023 #1

要计算节点数,我建议使用 xsl:number

此外,您尚未创建函数,而是创建了命名模板。在 XSLT 2.0+ 中,有实际的函数 (),因此正确使用术语非常重要。xsl:function

我不确定您使用的是哪个版本的 XSLT,所以这里有一个 1.0 示例......

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="ZDoc|TDoc">
        <xsl:copy>
            <seq><xsl:call-template name="get_seq"/></seq>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template name="get_seq">
        <xsl:variable name="to_count" select="name()"/>
        <xsl:number from="Item" count="*[name()=$to_count]"/>
    </xsl:template>
    
</xsl:stylesheet>