1. 概述
XML(可扩展标记语言)是跨多个平台和应用广泛使用的数据存储和传输格式。然而,尽管它功能强大,XML 仍存在处理文档中无效字符的问题。本文将探讨不同类型的无效字符以及在 XML 处理中如何处理它们。
2. XML 中的有效字符
XML 规范定义了元素内容和属性值中允许的字符。根据 XML 1.0 规范,以下是一些接受的字符范围和示例:
描述
范围
示例
制表符(水平制表符)
9 (TAB)
\t
换行符(新行)
10 (LF)
\n
回车符(返回到行首)
13 (CR)
\r
基本多语言平面(BMP)中的字符,排除代理块
32 至 55295
A, b, &, 1, α (希腊字母 alpha)
补充私用区-A(SMP)中的字符,排除代理块
57344 至 65533
😊 (微笑),🎉 (派对气球)
BMP 之外的补充平面中的字符
65536 至 1114111
🌍 (地球仪),🚀 (火箭)
注意:在 Unicode 中,我们使用特定的 UTF-16 编码代码点范围来表示超出基本多语言平面的字符。
3. XML 1.1 及其对无效字符的处理
XML 1.1 是 XML 1.0 的更新版本,提供了额外的灵活性,支持更广泛的字符集,包括整个 Unicode 字符集。它允许 1-31 范围内的字符(除制表符、换行符和回车符外),还包括某些控制字符,如 NEL(下一个行,Unicode 0x0085)。
4. XML 中的无效字符
XML 中的无效字符通常分为两类:
4.1. 保留字符
XML 在其语法中保留了一些字符,如 <
, >
, &
, "
, 和 '
。如果这些字符在没有正确编码的情况下出现在 XML 元素中,可能会干扰解析过程,使 XML 文档无效。例如:
@Test
void givenXml_whenReservedCharacters_thenThrowException() {
String invalidXmlString = "<?xml version=\"1.1\" encoding=\"UTF-8\"?><root><name>John & Doe</name></root>";
assertThrowsExactly(SAXParseException.class, () -> parseXmlString(invalidXmlString));
}
应使用预定义的字符实体正确转义保留字符。例如:
<
应编码为<
>
应编码为>
&
应编码为&
"
应编码为"
'
应编码为'
我们可以执行如下测试来验证:
@Test
void givenXml_whenReservedCharactersEscaped_thenSuccess() {
String validXmlString = "<?xml version=\"1.1\" encoding=\"UTF-8\"?><root><name>John & Doe</name></root>";
assertDoesNotThrow(() -> {
Document document = parseXmlString(validXmlString);
assertNotNull(document);
assertEquals("John & Doe", document.getElementsByTagName("name").item(0).getTextContent());
});
}
另一种处理保留字符的方法是使用 CDATA 段。它可以包含通常被解释为标记的文本块:
@Test
void givenXml_whenUsingCdataForReservedCharacters_thenSuccess() {
String validXmlString = "<?xml version=\"1.1\" encoding=\"UTF-8\"?><root><name><![CDATA[John & Doe]]></name></root>";
assertDoesNotThrow(() -> {
Document document = parseXmlString(validXmlString);
assertNotNull(document);
assertEquals("John & Doe", document.getElementsByTagName("name").item(0).getTextContent());
});
}
4.2. Unicode 字符
XML 文档使用 Unicode 进行编码,支持来自不同语言和脚本的大量字符。虽然 Unicode 提供了广泛的支持,但也包含与 XML 编码标准不兼容的字符,导致解析错误。
让我们看一个测试场景,其中我们在 XML 中包含了记录分隔符。Unicode 将记录分隔符表示为 \u001E
:
@Test
void givenXml_whenUnicodeCharacters_thenThrowException() {
String invalidXmlString = "<?xml version=\"1.1\" encoding=\"UTF-8\"?><root><name>John \u001E Doe</name></root>";
assertThrowsExactly(SAXParseException.class, () -> parseXmlString(invalidXmlString));
}
这个字符的 ASCII 值为 30,超出了接受范围。因此,解析此字符的测试会失败。为了正确处理非 ASCII 字符,我们应该使用如 UTF-8 或 UTF-16 等 Unicode 方案进行编码。
这样可以确保跨平台兼容性,并避免数据损坏问题。现在,让我们执行一个带有适当编码的测试:
@Test
void givenXml_whenUnicodeCharactersEscaped_thenSuccess() {
String validXmlString = "<?xml version=\"1.1\" encoding=\"UTF-8\"?><root><name>John  Doe</name></root>";
assertDoesNotThrow(() -> {
Document document = parseXmlString(validXmlString);
assertNotNull(document);
assertEquals("John \u001E Doe", document.getElementsByTagName("name").item(0).getTextContent());
});
}
5. 总结
本文探讨了 XML 中的不同无效字符及其处理方法。通过理解无效字符的原因并采用适当的策略,开发人员可以确保他们的 XML 处理管道的健壮性和可靠性。
如往常一样,完整的源代码可在 GitHub 上找到。