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
相关产品推荐
相关产品推荐

