Oracle XML解析报错:含无效非打印字符(U+1F600)求助
Oracle 11g XML解析错误(ORA-31011/LPX-00217)解决指南
问题背景
执行以下XML查询时触发解析错误:
SELECT X.CODE_VAL, X.CODE_DESC FROM DATA_TBL A, XML_TBL B, XMLTABLE('/XPATH/CHILDNODE1/CHILDNODE2' PASSING XMLTYPE(XML_TBL.XMLSTRING_TXT) COLUMNS CODE_VAL VARCHAR2(100) PATH 'PATH_TO_CODE_VAL', CODE_DESC VARCHAR2(2000) PATH 'PATH_TO_CODE_DESC' )X WHERE A.ID=B.ID AND A.ID='123' ;
报错信息:
ORA-31011: XML解析失败 ORA-19202: XML处理过程中发生错误 LPX-00217: 无效字符 128512 (U+1F600) 错误位于第663行 ORA-06512: 在 "SYS.XMLTYPE", line 272 ORA-06512: 在 line 1 31011.00000 - "XML解析失败" *原因: XML解析器解析文档时返回错误。 *操作: 检查要解析的文档是否有效。
已尝试设置会话NLS参数、转换输出列为ASCII、正则替换非打印字符,均未解决。数据库含130万条记录,数百条XML存在类似问题,定位困难。数据库版本:Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit
问题根源
Oracle 11g的XMLTYPE默认遵循XML 1.0规范,不支持U+10000及以上的Unicode补充平面字符(如示例中的U+1F600 emoji表情),这类字符会被判定为无效,导致解析失败。
解决方案
1. 定位问题XML记录
无需解析XML,直接通过字符串匹配筛选含无效字符的记录:
-- 方法1:匹配UTF-8四字节字符(补充平面字符的编码特征) SELECT B.ID, B.XMLSTRING_TXT FROM DATA_TBL A JOIN XML_TBL B ON A.ID = B.ID WHERE REGEXP_LIKE(B.XMLSTRING_TXT, '[' || CHR(240) || CHR(159) || ']'); -- 方法2:直接匹配目标无效字符U+1F600 SELECT B.ID, B.XMLSTRING_TXT FROM DATA_TBL A JOIN XML_TBL B ON A.ID = B.ID WHERE REGEXP_LIKE(B.XMLSTRING_TXT, UNISTR('\0001F600')); -- 方法3:筛选所有XML 1.0不允许的字符 SELECT B.ID, B.XMLSTRING_TXT FROM DATA_TBL A JOIN XML_TBL B ON A.ID = B.ID WHERE NOT REGEXP_LIKE(B.XMLSTRING_TXT, '^[\x09\x0A\x0D\x20-\x7E\xC0-\xD6\xD8-\xF6\xF8-\xFF]+$');
2. 处理解析错误
方案A:清理无效字符后解析
在创建XMLTYPE前,过滤掉XML 1.0不允许的字符,可直接用正则替换或自定义函数:
方式1:查询内直接正则替换
SELECT X.CODE_VAL, X.CODE_DESC FROM DATA_TBL A JOIN XML_TBL B ON A.ID = B.ID JOIN XMLTABLE('/XPATH/CHILDNODE1/CHILDNODE2' PASSING XMLTYPE( REGEXP_REPLACE(B.XMLSTRING_TXT, '[^\x09\x0A\x0D\x20-\x7E\xC0-\xD6\xD8-\xF6\xF8-\xFF]', '' ) ) COLUMNS CODE_VAL VARCHAR2(100) PATH 'PATH_TO_CODE_VAL', CODE_DESC VARCHAR2(2000) PATH 'PATH_TO_CODE_DESC' )X WHERE A.ID='123';
方式2:自定义清理函数
CREATE OR REPLACE FUNCTION CLEAN_XML_STR(p_str IN VARCHAR2) RETURN VARCHAR2 IS BEGIN RETURN REGEXP_REPLACE(p_str, '[^\x09\x0A\x0D\x20-\x7E\xC0-\xD6\xD8-\xF6\xF8-\xFF]', ''); END; /
使用函数的查询:
SELECT X.CODE_VAL, X.CODE_DESC FROM DATA_TBL A JOIN XML_TBL B ON A.ID = B.ID JOIN XMLTABLE('/XPATH/CHILDNODE1/CHILDNODE2' PASSING XMLTYPE(CLEAN_XML_STR(B.XMLSTRING_TXT)) COLUMNS CODE_VAL VARCHAR2(100) PATH 'PATH_TO_CODE_VAL', CODE_DESC VARCHAR2(2000) PATH 'PATH_TO_CODE_DESC' )X WHERE A.ID='123';
方案B:修改XML解析器参数(需补丁支持)
Oracle 11.2.0.3部分补丁(如13366211)支持设置解析器忽略无效字符,可通过以下方式实现:
会话级设置
ALTER SESSION SET EVENTS '31011 TRACE NAME CONTEXT FOREVER, LEVEL 1';
XMLTYPE构造函数指定选项
SELECT X.CODE_VAL, X.CODE_DESC FROM DATA_TBL A JOIN XML_TBL B ON A.ID = B.ID JOIN XMLTABLE('/XPATH/CHILDNODE1/CHILDNODE2' PASSING XMLTYPE(B.XMLSTRING_TXT, 1) -- 1表示忽略无效字符 COLUMNS CODE_VAL VARCHAR2(100) PATH 'PATH_TO_CODE_VAL', CODE_DESC VARCHAR2(2000) PATH 'PATH_TO_CODE_DESC' )X WHERE A.ID='123';
3. 长期解决方案
若条件允许,升级至Oracle 12c及以上版本,新版本对Unicode补充平面字符支持更完善,可原生解析含emoji等字符的XML文档。
内容的提问来源于stack exchange,提问作者LNC
相关产品推荐
相关产品推荐

