在数据处理和系统对接中,XML是一种常见的数据交换格式。当XML的文本内容里出现小于号、大于号、和号等字符时,解析器会将其误认为标签或实体标记,从而抛出格式异常。要正确解析包含特殊字符的XML,需要理解XML的转义规则和CDATA机制,并选用合适的解析方式。

XML中的特殊字符与转义
XML规范定义了五个必须转义的预定义实体,如果在普通文本节点中使用这些符号,应写成对应的字符引用:
| 字符 | 转义写法 | 说明 |
|---|---|---|
| < | < | 小于号 |
| > | > | 大于号 |
| & | & | 和号 |
| ' | ' | 单引号 |
| " | " | 双引号 |
例如,文本 a < b & c > d 在XML中应写为 a < b & c > d,否则解析会失败。
使用CDATA段包裹特殊内容
如果一段文本包含大量特殊字符,逐个转义很麻烦,可以使用CDATA段。CDATA内的所有内容都会被解析器当作纯字符数据,不会解析其中的标签或实体:
<message><![CDATA[若 a < b 且 b > c,则结果正确 & 可用]]></message>
注意CDATA不能嵌套,且结束标记 ]]> 不能出现在内容中。
Python解析示例
使用标准库xml.etree.ElementTree可以自动处理转义,无需手动替换:
import xml.etree.ElementTree as ET
xml_text = '<root><item>a < b & c</item></root>'
root = ET.fromstring(xml_text)
print(root.find('item').text) # 输出: a < b & c
cdata_xml = '<root><msg><![CDATA[价格 < 100 & 库存 > 0]]></msg></root>'
root2 = ET.fromstring(cdata_xml)
print(root2.find('msg').text) # 输出: 价格 < 100 & 库存 > 0
Java解析示例
Java的DocumentBuilder同样能正确处理特殊字符与CDATA:
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import java.io.ByteArrayInputStream;
public class XmlDemo {
public static void main(String[] args) throws Exception {
String xml = "<root><note><![CDATA[错误码 < 0 & 重试]]></note></root>";
Document doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(new ByteArrayInputStream(xml.getBytes("UTF-8")));
Node note = doc.getElementsByTagName("note").item(0);
System.out.println(note.getTextContent()); // 输出: 错误码 < 0 & 重试
}
}
总结建议
解析包含特殊字符的XML时,首先确认数据源是否已做转义或使用了CDATA。在生成XML时,应对动态文本做实体转义;在解析时,优先使用成熟的标准库而非正则匹配。这样既能避免格式错误,也能提升代码的健壮性和可维护性。