You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用XSLT contains函数引用变量时的节点过滤问题求助

问题描述

我正在学习XML/XSLT,若有错误之处敬请谅解。我尝试基于文件内的类型主列表过滤XML节点,将类型列表存入变量后,在contains函数中引用该变量时过滤结果不符合预期。

预期移除Alex和Jenny,但仅移除了Jenny,Alex的type为3被误判存在于列表中(实际是列表中的1603的字符3),推测contains是匹配单个字符而非完整类型,请问如何实现匹配完整类型?

XML文件

<?xml version="1.0" encoding="UTF-8"?>
<users>
<types>1600,1601,1602,1603</types>

<user><name>Joe</name><type>1600</type></user>
<user><name>Susan</name><type>1601</type></user>
<user><name>Alex</name><type>3</type></user>
<user><name>Jenny</name><type>4</type></user>
</users>

现有XSLT代码

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <users>
        <!-- store type list in variable -->
        <xsl:variable name="var_typelist" select="users/types"/>
        <!-- cycle through users -->
            <xsl:for-each select="users/user">
        <!-- store user data in a variable -->
            <xsl:variable name="var_user" select="*"></xsl:variable>
        <!-- check if user type matches one in the list -->
            <xsl:choose>
                <xsl:when test="contains($var_typelist,type)">
        <!-- rebuild file with user details -->
                    <users>
                        <xsl:copy-of select="$var_user"/>
                    </users>
                </xsl:when>
                <xsl:otherwise>
                </xsl:otherwise>
            </xsl:choose>
            </xsl:for-each> 
        </users>            
    </xsl:template>
</xsl:stylesheet>
解决方案

方法1:使用tokenize拆分类型列表(XSLT2.0+推荐)

contains是子字符串匹配,所以会把"3"误判为"1603"的一部分。XSLT2.0支持tokenize函数,可将逗号分隔的字符串拆分为字符串序列,直接判断用户类型是否属于该序列即可。

修改后的代码:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <users>
            <!-- 将类型列表拆分为字符串序列 -->
            <xsl:variable name="valid_types" select="tokenize(users/types, ',')"/>
            <!-- 直接筛选类型匹配的用户 -->
            <xsl:for-each select="users/user[type = $valid_types]">
                <user>
                    <xsl:copy-of select="*"/>
                </user>
            </xsl:for-each>
        </users>            
    </xsl:template>
</xsl:stylesheet>
  • tokenize(users/types, ',')会把1600,1601,1602,1603转换为序列('1600','1601','1602','1603')
  • 通过user[type = $valid_types]直接过滤出符合条件的用户,代码更简洁高效。

方法2:添加分隔符避免子字符串匹配

如果无法使用tokenize,可以给类型列表和用户类型前后都加上逗号,确保匹配的是完整的类型值。

修改后的判断逻辑及完整代码:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <users>
            <xsl:variable name="var_typelist" select="users/types"/>
            <!-- 给类型列表前后添加逗号,构建完整匹配的字符串 -->
            <xsl:variable name="full_typelist" select="concat(',', $var_typelist, ',')"/>
            <xsl:for-each select="users/user">
                <xsl:choose>
                    <!-- 判断带逗号包裹的用户类型是否存在于处理后的类型列表中 -->
                    <xsl:when test="contains($full_typelist, concat(',', type, ','))">
                        <user>
                            <xsl:copy-of select="*"/>
                        </user>
                    </xsl:when>
                </xsl:choose>
            </xsl:for-each> 
        </users>            
    </xsl:template>
</xsl:stylesheet>
  • 处理后的类型列表为,1600,1601,1602,1603,,用户类型"3"会变成,3,,此时contains只会匹配完整的,3,,而该值不在处理后的列表中,Alex会被正确过滤。

内容的提问来源于stack exchange,提问作者AJW

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 17:55:04