Анализ ответа веб-службы в Oracle 9i - PullRequest
2 голосов
/ 08 апреля 2010

У меня проблемы с анализом 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 в итоге становится нулевым.

-- 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)

Ответы [ 2 ]

0 голосов
/ 08 апреля 2010

Вот пример в PL / SQL, который извлекает эти значения другим способом. Одна вещь, которую я заметил из вашего XML-фрагмента, который вы разместили, это то, что вы пропустили закрывающий </soap:Envelope>

Это автономный пример, который вы можете запустить в SQL plus и увидеть результаты вызовов 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;
0 голосов
/ 08 апреля 2010

Ну, похоже, я нашел ответ.Вероятно, не самый лучший ответ, поэтому, пожалуйста, прокомментируйте, если вы знаете лучший (и / или более правильный) способ!

Мое решение (опять же, вероятно, не лучшее решение) состояло в том, чтобы действительно обойти запрос 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) определяется без псевдонима (пример: «мыло»). Я думаю, что моя первоначальная проблема исчезнет, ​​если узел GetMailDataResponse был определен следующим образом:

<a:GetMailDataResponse xmlns:a="https://www.customnamespacehost.com/webservicename">  
...