我在解析来自web服务的XML响应时遇到了困难。我有一种感觉,这是由于名称空间问题。但是,经过4个小时的研究、反复试验和脑震荡,我还没能解决这个问题。请帮帮忙。
我的目标是获得一个包含“错误”节点的dbms_xmldom.DOMNodeList。
XML响应:
<?xml version="1.0" encoding="ISO-8859-1"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetMailDataResponse xmlns="https://www.customnamespacehost.com/webservicename">
<GetMailDataResult>
<Errors xmlns="">
<ErrorDetail>Access Credentials Invalid</ErrorDetail>
</Errors>
</GetMailDataResult>
</GetMailDataResponse>
</soap:Body>
</soap:Envelope>代码:
不幸的是,这段代码编译但不能工作。
Error: "ORA-31013: Invalid XPATH expression. 我相信这是由于L_NS变量中定义的多个名称空间造成的。我尝试设置L_XPATH:/soap:Envelope/soap:Body和L_NS:xmlns:soap="http://schemas.xmlsoap.org/soap/envelope",但是L_NL_RESULTS最终为null。
-- Variable Declarations --
P_XML XMLTYPE;
L_CODE_NAME VARCHAR2(1000) := 'PKG_CIS_WS.FNC_STAGE_DATA';
L_XML_DOC dbms_xmldom.DOMDocument;
L_NL_RESULTS dbms_xmldom.DOMNodeList;
L_NL_DONOR_SCREENING_RESULTS dbms_xmldom.DOMNodeList;
L_N_RESULT dbms_xmldom.DOMNode;
L_XPATH VARCHAR2(4000);
L_NS VARCHAR2(4000);
L_TEMP VARCHAR2(4000);
-- Code Snippet --
L_XML_DOC := dbms_xmldom.newDOMDocument(P_XML);
L_XPATH := '/soap:Envelope/soap:Body/a:GetMailDataResponse/GetMailDataResult';
L_NS := 'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope"' ||
'xmlns:a="https://www.customnamespacehost.com/webservicename"';
L_NL_RESULTS := dbms_xslprocessor.selectNodes(
dbms_xmldom.makeNode(L_XML_DOC)
, L_XPATH
, L_NS);
if not DBMS_XMLDOM.ISNULL(L_NL_RESULTS) then
FOR RESULTS_REC IN 0 .. dbms_xmldom.getLength(L_NL_RESULTS) - 1 LOOP
L_N_RESULT := dbms_xmldom.item(L_NL_RESULTS, RESULTS_REC);
L_TEMP := dbms_xmldom.GETNODENAME(L_N_RESULT);
prc_bjm(L_CODE_NAME, 'L_TEMP = ' || L_TEMP, SQLCODE);
dbms_xslprocessor.valueOf(L_N_RESULT, 'Errors/ErrorDetail/text()', L_TEMP);
prc_bjm(L_CODE_NAME, 'L_TEMP = ' || L_TEMP, SQLCODE);
END LOOP;
else
prc_bjm(L_CODE_NAME, 'No nodes for: ' || L_XPATH || '(' || L_NS || ')', SQLCODE);
end if; -- if not DBMS_XMLDOM.ISNULL(L_NL_RESULTS)发布于 2010-04-07 23:40:37
看来我找到了答案。也许不是最好的答案,所以如果你知道一个更好的(和/或更恰当的)方式,请评论!
我的解决方案(可能不是最好的解决方案)是真正地绕过XPATH查询。我添加了一些外卡和名称空间的定义,从那里流出来的东西。
工作守则
L_XML_DOC := dbms_xmldom.newDOMDocument(P_XML);
L_XPATH := '/soap:Envelope/soap:Body/*[namespace-uri()="https://www.customnamespacehost.com/webservicename"]/*/*[namespace-uri()=""]/*';
L_NL_RESULTS := dbms_xslprocessor.selectNodes(
dbms_xmldom.makeNode(L_XML_DOC)
, L_XPATH);
dbms_xmldom.writetobuffer(L_XML_DOC, L_TEMP);
prc_bjm(L_CODE_NAME, 'L_TEMP = ' || L_TEMP, SQLCODE);
if not DBMS_XMLDOM.ISNULL(L_NL_RESULTS) then
FOR RESULTS_REC IN 0 .. dbms_xmldom.getLength(L_NL_RESULTS) - 1 LOOP
L_N_RESULT := dbms_xmldom.item(L_NL_RESULTS, RESULTS_REC);
L_TEMP := dbms_xmldom.GETNODENAME(L_N_RESULT);
prc_bjm(L_CODE_NAME, 'L_TEMP = ' || L_TEMP, SQLCODE);
dbms_xslprocessor.valueOf(L_N_RESULT, 'text()', L_TEMP);
prc_bjm(L_CODE_NAME, 'L_TEMP = ' || L_TEMP, SQLCODE);
END LOOP;
else
prc_bjm(L_CODE_NAME, 'No nodes for: ' || L_XPATH || '(' || L_NS || ')', SQLCODE);
end if; -- if not DBMS_XMLDOM.ISNULL(L_NL_RESULTS)另外,如果你知道为什么这样做,请评论。在我看来,名称空间(用于GetMailDataResponse节点)是在没有别名(例如:“soap”)的情况下定义的。如果将GetMailDataResponse节点定义为:
<a:GetMailDataResponse xmlns:a="https://www.customnamespacehost.com/webservicename"> 发布于 2010-04-08 00:25:44
下面是PL/SQL中的一个示例,它以不同的方式提取这些值。从您发布的XML片段中,我注意到一件事,就是您错过了一个即将结束的</soap:Envelope>。
这是一个自包含的示例,您可以在SQL中运行并查看来自put_line调用的输出。
set serveroutput on
declare
v_xml xmltype;
v_str varchar2(3000);
v_temp varchar2(1000);
begin
v_str := '<?xml version="1.0" encoding="ISO-8859-1"?>' ||
'<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">' ||
'<soap:Body>' ||
' <GetMailDataResponse xmlns="https://www.customnamespacehost.com/webservicename">' ||
' <GetMailDataResult>' ||
' <Errors xmlns="">' ||
' <ErrorDetail>Access Credentials Invalid</ErrorDetail>' ||
' <ErrorDetail>Foobar</ErrorDetail>' ||
' </Errors>' ||
' </GetMailDataResult>' ||
' </GetMailDataResponse>' ||
'</soap:Body></soap:Envelope>';
--load our string into an xmltype variable
v_xml := xmltype(v_str);
--loop through each ErrorDetail entry
for rec in (select value(x) txt
from table(XMLSequence(extract(v_xml, '//Errors/ErrorDetail'))) x
)
loop
--output the XML that was returned
dbms_output.put_line('xml_snippet: ' || rec.txt.getStringVal());
--pull the value out of that XML
select extractvalue(rec.txt, '//*')
into v_temp
from dual;
--display the value that was pulled out
dbms_output.put_line('xml_vlaue: ' || v_temp);
end loop;
end;https://stackoverflow.com/questions/2596445
复制相似问题