XSLT 2.0+ 用 replace() 替换字符串,需注意正则转义和 ‘g’ 标志实现全局替换;XSLT 1.0 需递归模板配合 subString-before/after 实现,须防无限递归;concat() 拼接要防空值,推荐 normalize-space() 或 XSLT 2.0 的 string-join()。

用 replace() 做字符串替换(XSLT 2.0+)
XSLT 1.0 没有原生替换函数,必须靠递归模板;2.0 起直接用 replace(),但要注意正则语法和转义规则。
-
replace($str, 'old', 'new')只替换第一个匹配项;要全局替换,必须加'g'标志:replace($str, 'old', 'new', 'g') - 点号
.、星号*、括号等在正则里有特殊含义,字面匹配需转义:比如替换字符串"a.b"中的".",得写成replace($str, '.', '_') - 如果被替换内容来自变量或表达式,确保它不是空节点或未定义值,否则
replace()报错或返回空字符串
XSLT 1.0 怎么安全做字符串替换
没有 replace() 就得手写递归模板,核心是用 substring-before() 和 substring-after() 切片,再拼回去。
- 必须检查是否还存在待替换子串,否则无限递归——典型判断是
contains($str, $old) - 只替换首次出现时,直接用
concat(substring-before($str, $old), $new, substring-after($str, $old)) - 全局替换必须递归调用自身,且每次处理完一个匹配后,把剩余部分作为新输入传入
- 性能敏感场景慎用——长文本 + 频繁替换会明显拖慢处理速度
字符串拼接用 concat(),但注意空值陷阱
concat() 是 XSLT 1.0 和 2.0 都支持的函数,但它对空节点或未计算出值的表达式很敏感——会直接拼出空字符串,而不是跳过。
- 比如
concat(//first-name, ' ', //middle-name, ' ', //last-name),当中间名缺失时,结果变成"John Smith"(两个空格) - 更健壮的做法是用
normalize-space()包一层:normalize-space(concat(...)),它会把连续空白压缩成单个空格,并去掉首尾空白 - 多个动态片段拼接时,优先考虑
string-join()(XSLT 2.0+),它接受序列和分隔符:string-join((//part1, //part2, //part3), '-')
拼接 + 替换混用时,顺序和作用域容易出错
先拼再替换,还是先替换再拼,结果可能完全不同。尤其当替换目标跨字段、或拼接内容含特殊字符时,逻辑边界很容易模糊。
- 例如想把
//title和//subtitle拼起来,再统一把所有"|"替换成" - ",就得确保拼接后的整个字符串传给replace(),而不是分别替换再拼 - 避免在
concat()内部嵌套复杂replace()调用,可读性差且调试困难;建议拆成变量赋值:,再对$full操作 - XSLT 处理器对嵌套深度有限制,过度嵌套
replace()或递归模板可能触发栈溢出(尤其 Saxon-B 或旧版 MSXML)
实际用的时候,先确认你的处理器支持哪个 XSLT 版本——很多遗留系统卡在 1.0,而 replace() 和 string-join() 这类便利函数根本不可用。