SAX Xml->SAXParseException在文档的元素内容中找到无效的 XML 字符 (Unicode: 0x10)

本文介绍了一种在使用SAX解析大型XML文件时遇到含有unicode字符导致SAXParseException的方法,通过设置继续解析选项,实现了忽略错误记录或特殊处理错误记录,避免了解析过程因错误而终止。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在用SAX解析xml时,遇到文件中含unicode字符,则会抛出SAXParseException。

<?xml version="1.0" encoding="UTF-8"?>
<books>
    <book id="12">
        <name>Spring in Action</name>
        <price>45.0</price>
    </book>
    <book id="15">
        <name>HG6201M     </name>
        <price>39.0</price>
    </book>
</books>
其实当文件较大时,部分某一条的数据并不是很重要,我们希望能够略过这条数据或对这条数据作特殊处理,而不是当遇到解析错误时终止解析。

参考如下:

MyHander handler = new MyHander();
InputStream is = Test.class.getClass().getResourceAsStream("/file/book.xml");
SAXParserFactory factory = SAXParserFactory.newInstance();
XMLReader reader = factory.newSAXParser().getXMLReader();
//关键设置
reader.setFeature("http://apache.org/xml/features/continue-after-fatal-error",true);
reader.setContentHandler(handler);
reader.setErrorHandler(handler);
reader.parse(new InputSource(is));

自定义Hander:

public class ParseXmlHandler extends DefaultHandler {

    private String tag;
    private StringBuffer sb = null;

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        tag = qName;
        sb = new StringBuffer();
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        tag = null;
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        if (tag != null) {
            if (sb == null) {
                System.out.println("error");
            } else {
                sb.append(ch, start, length);
                System.out.println(sb.toString());
            }
        }
    }

    @Override
    public void fatalError(SAXParseException e) throws SAXException {
        sb = null;
    }
}

源码解析:

1.查找到当解析错误时抛出异常的类

可以看到在XMLErrorReporter.java中有段代码,当fContinueAfterFatalError为false时则解析抛出异常。

case SEVERITY_FATAL_ERROR: {
    errorHandler.fatalError(domain, key, parseException);
    if (!fContinueAfterFatalError) {
       throw parseException;
    }
    break;
}
则应设置fContinueAfterFatalError为true,该类的setFeature方法则可以设置fContinueAfterFatalError的属性


查看其常量值进行对应的设置

    public static final String XERCES_FEATURE_PREFIX = "http://apache.org/xml/features/";
    public static final String CONTINUE_AFTER_FATAL_ERROR_FEATURE = "continue-after-fatal-error";


<think>我们正在查找XML规范中明确禁止使用的Unicode字符。根据引用[1]和引用[3]的信息,XML规范(特别是XML 1.0)禁止使用某些控制字符。具体来说: 1. 禁止使用Unicode值在0x000x1F(即十进制0到31)之间的控制字符,但以下三个字符除外: - 0x09(制表符,'\t') - 0x0A(换行符,'\n') - 0x0D(回车符,'\r') 2. 另外,XML 1.0还禁止使用0x7F(DEL字符)以及0xFFFE和0xFFFF(它们不是Unicode字符,用于指示字节顺序)。 3. XML 1.1规范放宽了一些限制,允许使用更多的控制字符,但要求它们必须以字符引用的形式出现(例如,使用`…`表示0x85)。然而,0x00仍然被禁止,并且0xFFFE和0xFFFF仍然被禁止。 根据引用[3]: > * Verify that no character has a hex value greater than 0xFFFD, or less than 0x20. > * Check that the character is not equal to the tab ("\t"), the newline ("\n"), the carriage return ("\r"), or is an invalid XML character below the range of 0x20. 因此,我们可以总结如下: **XML 1.0禁止的字符范围:** - 十六进制:0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F, 0xFFFE, 0xFFFF - 允许的字符0x09(制表符)、0x0A(换行符)、0x0D(回车符) **XML 1.1禁止的字符范围:** - 绝对禁止:0x00, 0xFFFE, 0xFFFF - 其他控制字符0x01-0x1F,除了0x09, 0x0A, 0x0D)可以使用字符引用的形式(如``)表示,但不能直接出现在字符数据中。 注意:在XML 1.1中,控制字符必须用字符引用的形式,而不能是直接字符。此外,在XML 1.1中,允许使用Unicode字符直到0x10FFFF(除了代理块和0xFFFE、0xFFFF)。 因此,在解析XML时,如果遇到这些禁止字符,就会抛出类似`org.xml.sax.SAXParseException: An invalid XML character (Unicode: 0x10) was found`的异常。 ### 总结表格 | 规范版本 | 禁止的字符(十六进制) | 允许的控制字符(可直接出现) | 特殊说明 | |----------|------------------------|------------------------------|----------| | XML 1.0 | 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F, 0xFFFE, 0xFFFF | 0x09 (制表符), 0x0A (换行符), 0x0D (回车符) | 0x7F(DEL)也被禁止 | | XML 1.1 | 0x00, 0xFFFE, 0xFFFF | 0x09, 0x0A, 0x0D | 其他控制字符0x01-0x1F)必须用字符引用形式 | ### 参考 - XML 1.0规范:https://www.w3.org/TR/xml/#charsets - XML 1.1规范:https://www.w3.org/TR/xml11/#charsets [^1]: 引用[1]中提到的异常`SAXParseException`表明在CDATA段中发现了无效XML字符Unicode:0x10),这属于禁止范围(0x0E-0x1F之间)。 [^3]: 引用[3]明确指出需要验证字符是否在0x00-0x20(除了制表符、换行符、回车符)以及大于0xFFFD的字符。 §§相关问题§§ 1. XML 1.0XML 1.1在字符集处理上有哪些主要区别? 2. 在Java中如何指定使用XML 1.1解析器来处理包含控制字符XML? 3. 如何检测并清理XML字符串中的非法Unicode字符?</think>### XML规范中禁止使用的Unicode字符列表 根据XML 1.0规范(W3C Recommendation)和实际解析错误分析,以下是XML中明确禁止使用的Unicode字符: #### ⚠️ 绝对禁止的字符范围 1. **控制字符(C0控制码)**: - `\u0000` - `\u0008` (0x00-0x08):空字符到退格符 - `\u000B` (0x0B):垂直制表符 - `\u000C` (0x0C):换页符 - `\u000E` - `\u001F` (0x0E-0x1F):包括`\u0010`(DLE)等控制符 2. **特殊限制字符**: - `\u007F` (0x7F):DEL删除符 - `\uFFFE` 和 `\uFFFF`:非字符(永久保留) #### ✅ 允许使用的控制字符(例外) - `\u0009` (0x09):水平制表符(Tab) - `\u000A` (0x0A):换行符(LF) - `\u000D` (0x0D):回车符(CR) #### 字符合法性验证规则 XML字符必须满足: ```math \text{合法字符} = \begin{cases} x \in [\text{0x09}, \text{0x0A}, \text{0x0D}] & \text{或} \\ x \in [\text{0x20}, \text{0xD7FF}] & \text{或} \\ x \in [\text{0xE000}, \text{0xFFFD}] & \text{或} \\ x \in [\text{0x10000}, \text{0x10FFFF}] \end{cases} ``` > **关键规范依据**:XML 1.0规范第2.2节明确定义字符范围为`#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]`[^1][^3]。任何超出此范围的字符都会导致解析异常,如`SAXParseException: An invalid XML character (Unicode: 0x10)`[^1]。 ### 非法字符示例 | 十六进制 | Unicode | 字符名称 | 是否合法 | |----------|---------|------------------|----------| | 0x00 | \u0000 | 空字符(NUL) | ❌ 禁止 | | 0x01 | \u0001 | 标题开始(SOH) | ❌ 禁止 | | 0x10 | \u0010 | 数据链路转义(DLE)| ❌ 禁止 | | 0x7F | \u007F | 删除符(DEL) | ❌ 禁止 | | 0xFFFF | \uFFFF | 非字符 | ❌ 禁止 | | 0x09 | \u0009 | 制表符(Tab) | ✅ 允许 | ### 处理建议 1. **预处理过滤**:解析前移除非法字符 ```java String cleanXML = xml.replaceAll("[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]", ""); ``` 2. **编码转换**:对二进制数据使用Base64编码 3. **规范升级**:XML 1.1允许部分控制字符(如`…`),但需显式声明版本: ```xml <?xml version="1.1" encoding="UTF-8"?> ``` > **注意**:XML 1.1对控制字符的支持有限且存在兼容性问题,推荐优先采用过滤方案[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值