Plsql 如何在PL/SQL中读取多个XML节点值

Plsql 如何在PL/SQL中读取多个XML节点值,plsql,Plsql,Soap响应 <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Body> <GetResponse xmlns="http://tempuri.org/"> <GetResult xmlns:a="http://schemas.datacontract.org/2004/07/CRM" xmlns:i="http://www.w3.

Soap响应

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
   <s:Body>
      <GetResponse xmlns="http://tempuri.org/">
         <GetResult xmlns:a="http://schemas.datacontract.org/2004/07/CRM" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
            <a:ResultHeader xmlns:b="http://schemas.datacontract.org/2004/07/CRM">
               <b:ResultCode>000</b:ResultCode>
               <b:ResultDescription>Successful</b:ResultDescription>
            </a:ResultHeader>
            <a:ResultMessage>
               <a:AServices>
                  <a:Service>
                     <a:Date>2016-08-18T11:13:19</a:Date>
                     <a:ServiceID>1</a:ServiceID>
                     <a:ServiceName>GG</a:ServiceName>
                     <a:ServiceType>CM</a:ServiceType>
                  </a:Service>
                  <a:Service>
                     <a:Date>2016-08-16T16:02:03</a:Date>
                     <a:ServiceID>3</a:ServiceID>
                     <a:ServiceName>Cricket</a:ServiceName>
                     <a:ServiceType>AS</a:ServiceType>
                  </a:Service>
               </a:AServices>
            </a:ResultMessage>
         </GetResult>
      </GetResponse>
   </s:Body>
</s:Envelope>
我需要读取两个节点的ServiceID。 如果服务节点是多个,那么我需要读取所有子节点ServiceId

现在我只能读取一个节点,如下所示:

IF(http_resp.status_code = 200) THEN
    -- Create XML type from response text
    x_clob1:= replace(substr(x_clob,instr(x_clob,'<a:Service>'),instr(x_clob,'</a:Service>')-instr(x_clob,'<a:Service>')+length('<a:Service>')+1),'a:',null);
    l_resp_xml := XMLType.createXML(x_clob1);          

    l_resp_serviceId   := l_resp_xml.EXTRACT('//Service/'||'ServiceID'||'/text()').getstringval();
    l_resp_ServiceName := l_resp_xml.EXTRACT('//Service/'||'ServiceName'||'/text()').getstringval();  
甚至如何在PL/SQL中读取结果代码和resultdisc

根据结果代码,我只需要检查服务节点。
请提供您的意见

以下是您如何向前迈进一步的方法:您的问题是您仅限于一项服务。以所有服务为例:

x_clob1:=replacesubstrx_clob,instrx_clob,,instrx_clob,-instrx_clob,+length+1,'a:',null

这将允许您处理两种服务:

declare 
  l_resp_xml XMLType;
  x_clob clob:=to_clob('
   <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
   <s:Body>
      <GetResponse xmlns="http://tempuri.org/">
         <GetResult xmlns:a="http://schemas.datacontract.org/2004/07/CRM" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
            <a:ResultHeader xmlns:b="http://schemas.datacontract.org/2004/07/CRM">
               <b:ResultCode>000</b:ResultCode>
               <b:ResultDescription>Successful</b:ResultDescription>
            </a:ResultHeader>
            <a:ResultMessage>
               <a:AServices>
                  <a:Service>
                     <a:Date>2016-08-18T11:13:19</a:Date>
                     <a:ServiceID>1</a:ServiceID>
                     <a:ServiceName>GG</a:ServiceName>
                     <a:ServiceType>CM</a:ServiceType>
                  </a:Service>
                  <a:Service>
                     <a:Date>2016-08-16T16:02:03</a:Date>
                     <a:ServiceID>3</a:ServiceID>
                     <a:ServiceName>Cricket</a:ServiceName>
                     <a:ServiceType>AS</a:ServiceType>
                  </a:Service>
               </a:AServices>
            </a:ResultMessage>
         </GetResult>
      </GetResponse>
   </s:Body>
</s:Envelope>
'); 
  x_clob1 clob;
  l_resp_serviceId varchar2(1000);
  l_resp_ServiceName varchar2(1000);
begin
    x_clob1:= replace(substr(x_clob,instr(x_clob,'<a:AServices>'),instr(x_clob,'</a:AServices>')-instr(x_clob,'<a:AServices>')+length('<a:AServices>')+1),'a:',null);
    l_resp_xml := XMLType.createXML(x_clob1); 

    l_resp_serviceId   := l_resp_xml.EXTRACT('//Service[1]/'||'ServiceID'||'/text()').getstringval();
    l_resp_ServiceName := l_resp_xml.EXTRACT('//Service[1]/'||'ServiceName'||'/text()').getstringval();  
    dbms_output.put_line(l_resp_serviceId||':'||l_resp_ServiceName);
    --    dbms_output.put_line(x_clob1);
    l_resp_serviceId   := l_resp_xml.EXTRACT('//Service[2]/'||'ServiceID'||'/text()').getstringval();
    l_resp_ServiceName := l_resp_xml.EXTRACT('//Service[2]/'||'ServiceName'||'/text()').getstringval();  
    dbms_output.put_line(l_resp_serviceId||':'||l_resp_ServiceName);
end;
我建议您使用XMLTABLE将XML映射到关系行和关系列。 您将为每个节点获得一行


第1行的错误可能重复ORA-30625:不允许对NULL自参数进行方法分派ORA-06512:在第145行,我在输出中看到While循环的第一个给定值..但它有8个服务节点,它应该在输出中给出8个值No,=1只是为了检查它是否存在。它确实在每个节点上循环。那么循环所有8个节点的条件是什么,在我的响应中,所有8个节点中的8个服务节点,我需要读取服务ID。请花时间测试它。我在这里做了,得到了预期的两行结果。我在xpath中添加了一个条件,现在我的示例仅当ResultCode='000'时才从服务节点返回信息。
declare 
  l_resp_xml XMLType;
  x_clob clob:=to_clob('
   .. test value
'); 
  x_clob1 clob;
  l_resp_serviceId varchar2(1000);
  l_resp_ServiceName varchar2(1000);
  i integer := 1;
begin

  x_clob1:= replace(substr(x_clob,instr(x_clob,'<a:AServices>'),instr(x_clob,'</a:AServices>')-instr(x_clob,'<a:AServices>')+length('<a:AServices>')+1),'a:',null);
  l_resp_xml := XMLType.createXML(x_clob1);    

  WHILE l_resp_xml.existsNode('//Service[' || i || ']') = 1 LOOP 
    l_resp_serviceId   := l_resp_xml.EXTRACT('//Service['||i||']/'||'ServiceID'||'/text()').getstringval();
    l_resp_ServiceName := l_resp_xml.EXTRACT('//Service['||i||']/'||'ServiceName'||'/text()').getstringval();  
    dbms_output.put_line(l_resp_serviceId||':'||l_resp_ServiceName);
    i := i + 1;
  END LOOP;
end;
DECLARE
    l_xml              XMLTYPE;
    l_resp_serviceId   VARCHAR2(100); 
    l_resp_ServiceName VARCHAR2(100);

    -- cursor for XMLTABLE, where we create a row for each <a:Service>  node, if ResultCode = '000'
    CURSOR my_cursor IS 
        SELECT *
        FROM XMLTABLE (XMLNAMESPACES(
                              DEFAULT  'http://tempuri.org/',
                              'http://schemas.xmlsoap.org/soap/envelope/' AS "s",
                              'http://schemas.datacontract.org/2004/07/CRM' AS "a",
                              'http://schemas.datacontract.org/2004/07/CRM' AS "b",
                              'http://www.w3.org/2001/XMLSchema-instance' AS "i"),
                              '/s:Envelope/s:Body/GetResponse/GetResult[a:ResultHeader/b:ResultCode = 000]/a:ResultMessage/a:AServices/a:Service'
                              PASSING l_xml
                              COLUMNS                 
                                  "Date"           VARCHAR2(100)  PATH 'a:Date',
                                  "ServiceID"      VARCHAR2(100)  PATH 'a:ServiceID',
                                  "ServiceName"    VARCHAR2(100)  PATH 'a:ServiceName',
                                  "ServiceType"    VARCHAR2(100)   PATH 'a:ServiceType');

BEGIN    
    -- just initialize variable 
    l_xml:= XMLTYPE('
        <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
           <s:Body>
              <GetResponse  xmlns="http://tempuri.org/">
                 <GetResult xmlns:a="http://schemas.datacontract.org/2004/07/CRM" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
                    <a:ResultHeader xmlns:b="http://schemas.datacontract.org/2004/07/CRM">
                       <b:ResultCode>000</b:ResultCode>
                       <b:ResultDescription>Successful</b:ResultDescription>
                    </a:ResultHeader>         
                    <a:ResultMessage>
                       <a:AServices>
                          <a:Service>
                             <a:Date>2016-08-18T11:13:19</a:Date>
                             <a:ServiceID>1</a:ServiceID>
                             <a:ServiceName>GG</a:ServiceName>
                             <a:ServiceType>CM</a:ServiceType>
                          </a:Service>
                          <a:Service>
                             <a:Date>2016-08-16T16:02:03</a:Date>
                             <a:ServiceID>3</a:ServiceID>
                             <a:ServiceName>Cricket</a:ServiceName>
                             <a:ServiceType>AS</a:ServiceType>
                          </a:Service>
                       </a:AServices>
                    </a:ResultMessage>
                 </GetResult>
              </GetResponse>
           </s:Body>
        </s:Envelope>');

   -- iterate over all records     
   FOR rec IN my_cursor LOOP
       l_resp_serviceId:= rec."ServiceID";
       l_resp_ServiceName:= rec."ServiceType";
       dbms_output.put_line('ServiceId='||l_resp_serviceId||', ServiceName='||l_resp_ServiceName);    
   END LOOP;
END;