XML作为一种常用的数据交换格式,对字符有严格的规范要求,部分特殊字符会被XML解析器识别为语法标记,若出现在内容中就会成为非法XML字符,导致解析出错。常见的非法字符包括小于号、大于号、和号、单引号、双引号,以及部分ASCII控制字符。

XML中常见的非法字符类型
首先需要明确哪些字符属于XML规范中的非法字符,避免处理时遗漏:
- 语法类非法字符:<、>、&、'、",这些字符在XML中有特殊语法含义,直接出现在元素内容或属性值中会破坏XML结构。
- 控制类非法字符:ASCII码中0-31(除制表符、换行符、回车符外)的控制字符,XML解析器无法正确识别这类字符。
处理非法XML字符的常用技巧
1. 字符转义
对于语法类的非法字符,最基础的处理方式是使用XML预定义的转义实体替换,替换规则如下:
| 原字符 | 转义后实体 |
|---|---|
| < | < |
| > | > |
| & | & |
| ' | ' |
| " | " |
以下是Java语言中实现字符转义的示例代码:
public class XmlEscapeUtil {
public static String escapeXml(String input) {
if (input == null) {
return null;
}
// 依次替换非法字符
return input.replace("&", "&")
.replace("<", "<")
.replace(">", ">")
.replace("'", "'")
.replace(""", """);
}
public static void main(String[] args) {
String content = "测试<标签>内容&特殊字符'"";
String escaped = escapeXml(content);
System.out.println(escaped);
// 输出:测试<标签>内容&特殊字符'"
}
}
2. 使用CDATA区块
如果内容中包含大量需要转义的字符,逐个替换会比较繁琐,此时可以使用CDATA区块包裹内容,CDATA内部的字符会被解析器当作纯文本处理,不会识别其中的XML语法标记。CDATA的语法格式为<![CDATA[内容]]>,需要注意CDATA内部不能包含字符串]]>,否则会提前结束区块。
以下是XML中使用CDATA的示例:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<content>
<![CDATA[
这里是包含大量特殊字符的内容:<div>测试</div> & 符号 '单引号' "双引号"
]]>
</content>
</root>
3. 过滤或替换控制字符
对于ASCII控制字符,转义实体无法处理,需要在生成XML前过滤掉这类字符,或者替换为合法字符。以下是Python中过滤控制字符的示例:
import re
def filter_control_chars(input_str):
if not input_str:
return input_str
# 匹配ASCII 0-31中除t(9)、n(10)、r(13)外的控制字符,替换为空
pattern = re.compile(r'[x00-x08x0bx0cx0e-x1f]')
return pattern.sub('', input_str)
content = "包含控制字符的内容x01x02测试"
filtered = filter_control_chars(content)
print(filtered) # 输出:包含控制字符的内容测试
不同场景的处理方案选择
在实际开发中可以根据场景选择合适的处理方式:
- 如果内容中特殊字符较少,优先使用字符转义,处理简单且兼容性好。
- 如果内容包含大量HTML片段、代码等内容,优先使用CDATA区块,减少转义的工作量。
- 如果数据来源不可控,可能包含控制字符,需要在生成XML前先过滤控制字符,再进行后续处理。
注意:如果需要在CDATA中输出]]>字符串,可以将其拆分为多个部分,比如<![CDATA[]]]]><![CDATA[>]]>,这样解析后会合并为正确的]]>字符串。