xslt默认保留所有纯空白文本节点,需用顶层全局清理并配合精准保留必要空白,否则导致position()错乱、xpath失灵等问题。

空白字符不处理就会“乱入”结果树
XML源文件里那些换行、缩进、空格,XSLT默认全当有效节点保留——哪怕它们只是写给人看的排版。结果就是:position()算错序号、normalize-space()补救不过来、HTML输出多出空行、XPath匹配突然失灵。这不是bug,是XSLT的默认行为:**所有纯空白文本节点(只含空格/制表符/换行)都原样进入结果树**。
- 典型现象:两个
<chapter></chapter>之间有换行,position()返回2和4而不是1和2 - 根源不是你的XSLT写错了,而是处理器把换行当成了真实文本节点
-
<strip-space></strip-space>不是“美化输出”,而是提前从解析阶段就剔除这些无意义节点
怎么用 <strip-space></strip-space> 才真正生效
它必须是<stylesheet></stylesheet>的直接子元素,且只能在顶层声明;写在<template></template>里或嵌套在其他指令中完全无效。
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:strip-space elements="*"/> <xsl:output method="xml" indent="yes"/> <p><xsl:template match="@<em>|node()"> <xsl:copy> <xsl:apply-templates select="@</em>|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
-
elements="*"是最安全的起点——先全局清理,再用<preserve-space></preserve-space>放行需要格式的元素 - 不要混用通配符和具体名,比如
elements="* code":不同处理器解析顺序不一致,可能失效 - 它只删“纯空白节点”,不影响
<title> Hello </title>里文字前后的空格(那是混合文本的一部分)
为什么必须搭配 <preserve-space></preserve-space> 才可靠
你不可能真的“全删”——代码块、诗歌、配置片段一旦被<strip-space></strip-space>扫掉缩进和换行,内容就废了。所以白名单策略才是正解:先清空,默认不留空白;再精准加回。
-
<preserve-space elements="code pre poem textarea"></preserve-space>必须写在<strip-space></strip-space>之后,且同级 - 当一个元素同时被两者声明时,
<preserve-space></preserve-space>优先——这是W3C规范明确保证的 - 别指望靠
<text></text>或normalize-space()后期补救:前者只能加空白,后者会吃掉所有内部空格,无法还原原始缩进
常见踩坑点:你以为删了,其实没删
最常被忽略的是作用域和时机问题——<strip-space></strip-space>只影响**源XML解析阶段**,对模板里用<value-of></value-of>拼出来的字符串、或动态生成的文本完全无效。
- 错误写法:
<strip-space elements="book"></strip-space>,但源XML里实际是<book></book>(大小写敏感) - 错误位置:把它放在
<template></template>内部,等于没写 - 混淆概念:以为它会影响
<output indent="yes"></output>——后者是输出时自动加缩进,和源空白处理无关 - 调试技巧:用Saxon或Xalan的调试模式查看输入树(input tree),确认纯空白节点是否已被剥离
XSLT处理空白从来不是“要不要删”的选择题,而是“在哪删、为谁留、谁优先”的精确控制——漏掉<strip-space></strip-space>,后面所有模板都可能在跟幽灵空白较劲。










