XML作为常用的数据交换格式,其规范中对空白字符的处理有明确的定义,空白字符包含空格、制表符、回车符和换行符,这些字符在XML文档的不同位置会有不同的处理逻辑,很多解析异常或者数据偏差都和空白处理规则不熟悉有关。

XML空白处理的核心规则
XML规范将空白分为两类,分别是有意义空白和无意义空白,两者的处理规则完全不同。
无意义空白
无意义空白指的是出现在标记之间的空白,也就是元素标签外部、注释外部、处理指令外部的空白,这类空白在XML解析时会被忽略,不会进入解析后的数据结构中。
比如下面这段XML代码:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item>内容1</item>
<item>内容2</item>
</root>
其中<root>和第一个<item>之间的换行和缩进空白,两个<item>元素之间的换行和缩进空白,以及最后一个<item>和</root>之间的换行和缩进空白,都属于无意义空白,解析时会被直接丢弃。
有意义空白
有意义空白指的是出现在元素内容中的空白,也就是开标签和闭标签之间的空白,这类空白默认会被保留,但是如果元素被声明为xml:space="default",或者解析器开启了空白压缩配置,可能会被处理。
XML规范提供了xml:space属性来控制元素内容的空白处理行为,该属性有两个可选值:
- default:表示由应用程序自行决定如何处理该元素内的空白,通常解析器会压缩连续的空白为一个空格。
- preserve:表示必须保留该元素内的所有空白,不能做任何修改。
不同解析场景下的空白处理表现
DOM解析的空白处理
使用DOM解析XML时,默认情况下会保留元素内容中的空白,但是标记之间的空白会被解析为空的文本节点,需要开发者手动过滤。
下面是Java使用DOM解析XML处理空白的示例代码:
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class XmlWhitespaceDemo {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 开启忽略空白节点的配置,只会过滤标记之间的无意义空白
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse("test.xml");
Element root = doc.getDocumentElement();
NodeList children = root.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
// 只处理元素节点,过滤掉文本节点
if (node.getNodeType() == Node.ELEMENT_NODE) {
System.out.println("元素名称:" + node.getNodeName() + ",内容:" + node.getTextContent());
}
}
}
}
如果注释掉factory.setIgnoringElementContentWhitespace(true);这行代码,那么标记之间的空白会被解析为文本节点,遍历子节点时会输出很多空的文本内容。
SAX解析的空白处理
SAX解析是事件驱动的解析方式,空白内容会通过characters方法回调,开发者需要在回调中判断当前空白是否需要保留。
下面是Python使用SAX解析XML处理空白的示例代码:
import xml.sax
class XmlHandler(xml.sax.ContentHandler):
def __init__(self):
self.current_element = ""
self.preserve_space = False
def startElement(self, name, attrs):
self.current_element = name
# 判断当前元素是否设置了xml:space="preserve"
if "xml:space" in attrs and attrs["xml:space"] == "preserve":
self.preserve_space = True
else:
self.preserve_space = False
def characters(self, content):
# 如果内容全是空白且不需要保留,直接忽略
if not self.preserve_space and content.strip() == "":
return
print(f"元素{self.current_element}的内容:{content}")
parser = xml.sax.make_parser()
parser.setContentHandler(XmlHandler())
parser.parse("test.xml")
特殊场景的空白处理注意事项
当XML中混合了xml:space="preserve"的元素和普通元素时,需要注意空白的处理范围,xml:space属性只对其所在的元素及其子元素生效,不会影响父元素或者其他兄弟元素。
另外如果XML文档中需要保留特殊空白,比如代码块中的缩进、诗歌的换行,一定要给对应的元素添加xml:space="preserve"属性,否则解析后空白会被压缩,导致内容格式丢失。
下面是带有xml:space属性的XML示例:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<normal> 多个 空格 会被压缩 </normal>
<code xml:space="preserve">
def test():
print("hello")
</code>
</root>
解析后normal元素的内容会变成"多个 空格 会被压缩",而code元素的内容会完整保留换行和缩进空白。
XML空白处理whitespace_handlingXML解析修改时间:2026-07-12 06:39:25