在APEX中将CLOB转换为XMLTYPE时遭遇ORA-06512数值/值错误
问题分析与解决思路
问题重现
我有一个名为ws_get_test的PL/SQL函数,返回CLOB格式的SOAP响应。在APEX页面中执行以下代码时,l_xml XMLTYPE := XMLTYPE(l_xml_response);这行会抛出ORA-06512数值或值错误,但相同逻辑在SQL Developer中执行完全正常:
DECLARE l_xml_response CLOB; l_xml XMLTYPE; BEGIN select ws_get_test(p_no => '12345' ) into l_xml_response from dual; l_xml XMLTYPE := XMLTYPE(l_xml_response); END;
ws_get_test函数代码如下:
create or replace function ws_get_test(p_no varchar2) return clob as l_envelope CLOB; l_xml XMLTYPE; l_result clob; begin l_envelope := '<soapenv:Envelope xmlns:soapenv="http:schemas.xmlsoap.org/soap/envelope/" xmlns:wsei="http://wsei.test.com"> <soapenv:Header/> <soapenv:Body> <wsei:CatchData> <wsei:lk_no>' || p_no || '</wsei:lk_no> </wsei:CatchData> </soapenv:Body> </soapenv:Envelope>'; l_xml :=APEX_WEB_SERVICE.make_request( p_url => 'http://example.com/services/DS_CatchData', p_action => 'urn:CatchData', p_envelope => l_envelope ); l_result := APEX_WEB_SERVICE.parse_xml_clob( p_xml =>remove_namespace(l_xml), p_xpath =>'/Envelope/Body/Data', p_ns=> '' ); return l_result; END;
核心原因排查方向
1. 环境差异导致的响应异常
- 字符集不匹配:APEX与SQL Developer的数据库/会话字符集不一致,CLOB中的XML包含非法字符,无法被XMLTYPE解析。
- Web服务访问差异:APEX环境的网络权限、代理设置和SQL Developer不同,调用
APEX_WEB_SERVICE.make_request时返回的不是合法XML(比如错误页面、空响应)。
2. 自定义函数remove_namespace的结构破坏
该函数的实现可能在处理XML时破坏了文档结构,比如遗漏标签闭合、引入不可见字符,导致最终返回的CLOB不是合法XML。
3. XMLTYPE构造的格式限制
如果l_xml_response为空、存在未转义的特殊字符(如&未转义为&),或者XML结构不完整,都会触发数值或值错误。
解决步骤
步骤1:捕获详细错误信息
在APEX代码中添加异常处理,打印具体错误和响应片段,定位问题根源:
DECLARE l_xml_response CLOB; l_xml XMLTYPE; BEGIN select ws_get_test(p_no => '12345' ) into l_xml_response from dual; l_xml := XMLTYPE(l_xml_response); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('错误信息: ' || SQLERRM); -- 打印响应前500字符,确认是否为合法XML DBMS_OUTPUT.PUT_LINE('响应内容片段: ' || DBMS_LOB.SUBSTR(l_xml_response, 500)); END;
步骤2:验证remove_namespace函数逻辑
检查该自定义函数的实现,确保它不会破坏XML结构。可以在SQL Developer中执行以下代码对比处理前后的XML:
DECLARE l_test_xml XMLTYPE := XMLTYPE('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><Data>test</Data></soapenv:Body></soapenv:Envelope>'); BEGIN DBMS_OUTPUT.PUT_LINE('处理前: ' || l_test_xml.getClobVal()); DBMS_OUTPUT.PUT_LINE('处理后: ' || remove_namespace(l_test_xml).getClobVal()); END;
步骤3:对比APEX与SQL Developer的Web服务响应
在APEX中直接调用Web服务并输出原始响应,确认和SQL Developer的返回是否一致:
DECLARE l_envelope CLOB; l_xml XMLTYPE; BEGIN l_envelope := '<soapenv:Envelope xmlns:soapenv="http:schemas.xmlsoap.org/soap/envelope/" xmlns:wsei="http://wsei.test.com"> <soapenv:Header/> <soapenv:Body> <wsei:CatchData> <wsei:lk_no>12345</wsei:lk_no> </wsei:CatchData> </soapenv:Body> </soapenv:Envelope>'; l_xml :=APEX_WEB_SERVICE.make_request( p_url => 'http://example.com/services/DS_CatchData', p_action => 'urn:CatchData', p_envelope => l_envelope ); DBMS_OUTPUT.PUT_LINE('Web服务原始响应: ' || l_xml.getClobVal()); END;
步骤4:修复字符集或XML格式问题
如果是字符集不匹配,转换CLOB字符集后再构造XMLTYPE(根据实际环境调整字符集参数):
l_xml := XMLTYPE(UTL_I18N.CONVERT(l_xml_response, 'AL32UTF8', 'WE8ISO8859P1'));
如果是XML格式问题,检查APEX_WEB_SERVICE.parse_xml_clob的XPath是否正确,确保返回的l_result是完整合法的XML片段。
内容的提问来源于stack exchange,提问作者hancho
相关产品推荐
相关产品推荐

