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

XPath中原子值与节点混淆问题及简便解决方法(Saxon PE 11.4)

XPath原子值序列批量转换大写的实现方案

问题场景

使用Saxon PE 11.4进行XSLT 2.0开发时,需要将字符串序列('a','b','D')通过单个XPath表达式全部转换为大写序列。

原可行代码(通过<xsl:for-each>遍历后逐个转换):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
    
    <xsl:output method="xml" indent="yes"/>
    
    <xsl:template match="/">
        <root>
            <xsl:for-each select="('a','b','D')">
                <string>
                    <xsl:value-of select="upper-case(.)"/>
                </string>
            </xsl:for-each>
        </root>
    </xsl:template>
</xsl:stylesheet>

输入任意XML(如<root/>)后,输出符合预期:

<root>
   <string>A</string>
   <string>B</string>
   <string>D</string>
</root>

错误尝试与原因

尝试用('a','b','D')/upper-case(.)作为select表达式时,报错:

The required item type of the first operand of '/' is node(). The supplied value is an atomic value

原因是**/运算符要求左操作数必须是节点类型**,而这里传入的是字符串原子值序列,不符合语法要求。

解决方案

方案1:直接将序列传入upper-case()函数(XSLT 2.0兼容)

XPath 2.0及以上版本的函数支持接收序列参数,会自动对序列中的每个原子值逐一处理,返回转换后的新序列:

修改后的代码如下:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
    
    <xsl:output method="xml" indent="yes"/>
    
    <xsl:template match="/">
        <root>
            <xsl:for-each select="upper-case(('a','b','D'))">
                <string>
                    <xsl:value-of select="."/>
                </string>
            </xsl:for-each>
        </root>
    </xsl:template>
</xsl:stylesheet>

运行后会得到与原代码完全一致的正确输出。

方案2:使用!运算符(XPath 3.0+兼容,Saxon PE 11.4支持)

!运算符是XPath 3.0引入的简单映射运算符,专门用于对序列中的每个原子值或节点执行操作,写法更直观:

('a','b','D')!upper-case(.)

对应的XSLT代码:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="3.0">
    
    <xsl:output method="xml" indent="yes"/>
    
    <xsl:template match="/">
        <root>
            <xsl:for-each select="('a','b','D')!upper-case(.)">
                <string>
                    <xsl:value-of select="."/>
                </string>
            </xsl:for-each>
        </root>
    </xsl:template>
</xsl:stylesheet>

这种写法更适合需要对序列中每个元素执行复杂自定义操作的场景。


内容的提问来源于stack exchange,提问作者MrD at KookerellaLtd

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 19:45:36