Oracle PLSQL调用第三方SOAP Web Services时,需要使Oracle内置一些XML解析函数,它可以很方便的解析SOAP Web Services返回XML内容,下面介绍常用XML内置函数和使用方法:
- EXTRACT(XMLType_instance,XPath_string,[namespace_string])用法
该函数用于获得XML某节点或某节点集
1.1 获得Cities节点内容
1.2 获得带名空间的节点的内容SELECT Extract(Xmltype('<?xml version="1.0" encoding="utf-8"?> <Root> <Cities> <City><Id>1</Id><CityName>北京市</CityName><ZipCode>100000</ZipCode></City> <City><Id>2</Id><CityName>天津市</CityName><ZipCode>100001</ZipCode></City> <City><Id>3</Id><CityName>石家庄市</CityName><ZipCode>050000</ZipCode></City> <City><Id>4</Id><CityName>唐山市</CityName><ZipCode>063000</ZipCode></City> <City><Id>5</Id> <CityName>秦皇岛市</CityName><ZipCode>066000</ZipCode></City> <City><Id>6</Id><CityName>邯郸市</CityName><ZipCode>056000</ZipCode></City> </Cities> </Root>') ,'/Root/Cities') FROM Dual;
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 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" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 为命名空间。SELECT Extract(Xmltype('<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <MFCRequest> <Cities> <City><Id>1</Id><CityName>北京市</CityName><ZipCode>100000</ZipCode></City> <City><Id>2</Id><CityName>天津市</CityName><ZipCode>100001</ZipCode></City> <City><Id>3</Id><CityName>石家庄市</CityName><ZipCode>050000</ZipCode></City> <City><Id>4</Id><CityName>唐山市</CityName><ZipCode>063000</ZipCode></City> <City><Id>5</Id> <CityName>秦皇岛市</CityName><ZipCode>066000</ZipCode></City> <City><Id>6</Id><CityName>邯郸市</CityName><ZipCode>056000</ZipCode></City> </Cities> </MFCRequest> </soap:Body> </soap:Envelope>'),'/soap:Envelope/soap:Body/MFCRequest','xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"') from dual;
参考官方API:https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions051.htm
- EXTRACTVALUE(XMLType_instance,XPath_string,[namespace_string])用法
该函数用于返回特定XML节点路径的数据
2.1 获某元素的值SELECT Extractvalue(Xmltype('<?xml version="1.0" encoding="utf-8"?> <Root> <Cities> <City> <Id>1</Id><CityName>北京市</CityName><ZipCode>100000</ZipCode> </City> </Cities> </Root>') ,'/Root/Cities/City/CityName') FROM Dual;
2.2 获某带命名空间XML中某元素的值SELECT Extractvalue(Xmltype('<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <MFCRequestResponse> <MFCRequestResult> <IsSuccessed>false</IsSuccessed> <Message>用户验证失败</Message> </MFCRequestResult> </MFCRequestResponse> </soap:Body> </soap:Envelope>') ,'/soap:Envelope/soap:Body/MFCRequestResponse/MFCRequestResult/IsSuccessed' ,'xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"') FROM Dual;
注意:EXTRACTVALUE只能解析单一XML叶子节点的值。不能解析根节点和子节点的内容,或多个相同XML叶子节点的值
参考官方API:https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions052.htm#i1131042 - 表转换XML
3.1 DBMS_XMLGEN.GETXML 表转换XML
结果:SELECT Dbms_Xmlgen.Getxml('SELECT Msi.Segment1 Item_Num ,Msi.Description Item_Desc ,Msi.Primary_Unit_Of_Measure UOM FROM Mtl_System_Items_b Msi WHERE Msi.Organization_Id = 82 AND Rownum <= 30') FROM Dual;
1.默认根元素为<ROWSET>和每行的节点元素为<ROW>
2.列名或列别名为各个值的元素
参考官方API:https://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_xmlgen.htm#i1012053
3.2 XMLELEMENT、XMLFOREST和XMLAGG结合使用
XMLAGG 函数用于汇总所有XML文档,并生成一个XML文档。SELECT XMLELEMENT("ITEMS" ,Xmlagg(Xmlelement("ITEM" ,XMLFOREST(Msi.Segment1 Item_Number ,Msi.Description Item_Desc)))) FROM Mtl_System_Items_b Msi WHERE Msi.Organization_Id = 82 AND Rownum <= 10;
参考官方API:https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions215.htm
3.3 二层或多层级XML结构实例,如BOM清单:
输出结果如下:SELECT Xmlelement("BOMS" --第一层 ,Xmlagg(Xmlelement("BOM" --第二层 ,Xmlforest(Bbm.Bill_Sequence_Id ,Bbm.Organization_Id ,Bbm.Assembly_Item_Id ,Msi.Segment1 Assembly_Item ,Msi.Description Assembly_Desc) ----Componentes Start--------------------- ,(SELECT Xmlelement("COMPONENTS" ,Xmlagg(Xmlelement("COMPONENT" ,Xmlforest(Bic.Component_Sequence_Id ,Bic.Component_Item_Id ,Msi.Segment1 Component_Item ,Msi.Description Component_Desc)))) AS Components FROM Bom_Inventory_Components Bic ,Mtl_System_Items_b Msi WHERE Bic.Component_Item_Id = Msi.Inventory_Item_Id AND Bic.Effectivity_Date <= SYSDATE AND Nvl(Bic.Disable_Date, SYSDATE) >= Trunc(SYSDATE) AND Bic.Bill_Sequence_Id = Bbm.Bill_Sequence_Id AND Msi.Organization_Id = Bbm.Organization_Id) ----Componentes End--------------------- ))) FROM Bom_Bill_Of_Materials Bbm ,Mtl_System_Items_b Msi WHERE Bbm.Assembly_Item_Id = Msi.Inventory_Item_Id AND Bbm.Organization_Id = Msi.Organization_Id AND Bbm.Bill_Sequence_Id IN (SELECT DISTINCT Bic.Bill_Sequence_Id FROM Bom_Inventory_Components Bic WHERE Bic.Effectivity_Date <= SYSDATE AND Nvl(Bic.Disable_Date, SYSDATE) >= Trunc(SYSDATE) AND Rownum < 2);
<BOMS> <BOM> <BILL_SEQUENCE_ID>1</BILL_SEQUENCE_ID> <ORGANIZATION_ID>83</ORGANIZATION_ID> <ASSEMBLY_ITEM_ID>3</ASSEMBLY_ITEM_ID> <ASSEMBLY_ITEM>1110010001</ASSEMBLY_ITEM> <ASSEMBLY_DESC>子装配件</ASSEMBLY_DESC> <COMPONENTS> <COMPONENT> <COMPONENT_SEQUENCE_ID>2</COMPONENT_SEQUENCE_ID> <COMPONENT_ITEM_ID>1</COMPONENT_ITEM_ID> <COMPONENT_ITEM>WD01</COMPONENT_ITEM> <COMPONENT_DESC>家用电器</COMPONENT_DESC> </COMPONENT> <COMPONENT> <COMPONENT_SEQUENCE_ID>3</COMPONENT_SEQUENCE_ID> <COMPONENT_ITEM_ID>2</COMPONENT_ITEM_ID> <COMPONENT_ITEM>WD02</COMPONENT_ITEM> <COMPONENT_DESC>家用电扇</COMPONENT_DESC> </COMPONENT> </COMPONENTS> </BOM> </BOMS>
- XMLTABLE([XML_namespace],XQuery_string,XMLTABLE_options)(XML转换表用法)
4.1 XML转换表SELECT * FROM Xmltable('/Cities/City' Passing Xmltype('<?xml version="1.0" encoding="utf-8"?> <Cities> <City><Id>1</Id><CityName>北京市</CityName><ZipCode>100000</ZipCode></City> <City><Id>2</Id><CityName>天津市</CityName><ZipCode>100001</ZipCode></City> <City><Id>3</Id><CityName>石家庄市</CityName><ZipCode>050000</ZipCode></City> <City><Id>4</Id><CityName>唐山市</CityName><ZipCode>063000</ZipCode></City> <City><Id>5</Id> <CityName>秦皇岛市</CityName><ZipCode>066000</ZipCode></City> <City><Id>6</Id><CityName>邯郸市</CityName><ZipCode>056000</ZipCode></City> </Cities>') Columns City_Id NUMBER Path '/City/Id' ,City_Name VARCHAR2(240) Path '/City/CityName' ,Zip_Code VARCHAR2(10) Path '/City/ZipCode')
4.2 XML转表带命名空间SELECT * FROM XMLTABLE(XMLNAMESPACES('http://schemas.xmlsoap.org/soap/envelope/' AS "soapenv1", 'http://platform.nucleusconnect.com/wsdl/EUCServices' AS "euc1"), '$B/soapenv1:Envelope/soapenv1:Body/euc1:EUCRevisionNewOrderRequest/body' PASSING (select xmltype('<?xml version="1.0" encoding="utf-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:euc="http://platform.nucleusconnect.com/wsdl/EUCServices"> <soapenv:Body> <euc:EUCRevisionNewOrderRequest> <header> <Department>Business Solution - Business Broadband</Department> <AcceptTNC>Yes</AcceptTNC> <TransactionId>FB000120170119181518436</TransactionId> </header> <body> <SalesOrderId>2017011914381897</SalesOrderId> </body> <body> <SalesOrderId>2017011914381897</SalesOrderId> </body> </euc:EUCRevisionNewOrderRequest> </soapenv:Body> </soapenv:Envelope>') from dual a ) AS B COLUMNS SalesOrderId VARCHAR2(128) PATH '/body/SalesOrderId')
参考官方API:https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions228.htm - EXISTSNODE(XMLType_instance,XPath_string,namespace_string)用法
该函数用于确定特定的XML节点的路径是否存在,返回0表示节点不存在,返回1表示节点存在。
如下:判断XML中/Cities/City下Id元素为2的值是否存在WITH Xmlcities AS (SELECT Xmltype('<?xml version="1.0" encoding="utf-8"?> <Cities> <City><Id>1</Id><CityName>北京市</CityName><ZipCode>100000</ZipCode></City> <City><Id>2</Id><CityName>天津市</CityName><ZipCode>100001</ZipCode></City> <City><Id>3</Id><CityName>石家庄市</CityName><ZipCode>050000</ZipCode></City> <City><Id>4</Id><CityName>唐山市</CityName><ZipCode>063000</ZipCode></City> <City><Id>5</Id> <CityName>秦皇岛市</CityName><ZipCode>066000</ZipCode></City> <City><Id>6</Id><CityName>邯郸市</CityName><ZipCode>056000</ZipCode></City> </Cities>') AS Xml_Object FROM Dual) SELECT * FROM Xmlcities T1 WHERE Existsnode(Xml_Object, '/Cities/City[Id="2"]') = 1
- 无法表格化的XML解析实例脚本
DECLARE --创建XML解析器实例XMLPARSER.parser Xmlpar Xmlparser.Parser := Xmlparser.Newparser; --定义DOM文档对象 Xmldoc Xmldom.Domdocument; --定义解析XML所需要的其他对象 Lo_City_Nodelist Xmldom.Domnodelist; --City节点集 Lo_City_Node Xmldom.Domnode; --City节点 Ln_City_Count NUMBER; Chilnodes Xmldom.Domnodelist; --City节点下元素 Ln_City_Id NUMBER; Lv_City_Name VARCHAR2(240); Lv_Zip_Code VARCHAR2(10); Xmlclobdata CLOB := '<?xml version="1.0" encoding="utf-8"?> <Cities> <City><Id>1</Id><CityName>北京市</CityName><ZipCode>100000</ZipCode></City> <City><Id>2</Id><CityName>天津市</CityName><ZipCode>100001</ZipCode></City> <City><Id>3</Id><CityName>石家庄市</CityName><ZipCode>050000</ZipCode></City> <City><Id>4</Id><CityName>唐山市</CityName><ZipCode>063000</ZipCode></City> <City><Id>5</Id> <CityName>秦皇岛市</CityName><ZipCode>066000</ZipCode></City> <City><Id>6</Id><CityName>邯郸市</CityName><ZipCode>056000</ZipCode></City> </Cities>'; BEGIN --创建XML解析对象 Xmlpar := Xmlparser.Newparser; BEGIN --解析文档并创建一个新的DOM文档。 Xmlparser.Parseclob(Xmlpar, Xmlclobdata); EXCEPTION WHEN OTHERS THEN Dbms_Output.Put_Line('Xml文件格式错误或者不完整'); RETURN; END; --获得XML文档 Xmldoc := Xmlparser.Getdocument(Xmlpar); --释放解析器实例 Xmlparser.Freeparser(Xmlpar); --获取所有City节点 Lo_City_Nodelist := Xmldom.Getelementsbytagname(Xmldoc, 'City'); --获得City节点个数 Ln_City_Count := Xmldom.Getlength(Lo_City_Nodelist); Dbms_Output.Put_Line('Ln_City_Count:' || Ln_City_Count); --遍历City节点 FOR i IN 0 .. Ln_City_Count - 1 LOOP --获得City节点 Lo_City_Node := Xmldom.Item(Lo_City_Nodelist, i); Chilnodes := Xmldom.Getchildnodes(Lo_City_Node); --获取City节点元素 Ln_City_Id := Xmldom.Getnodevalue(Xmldom.Getfirstchild(Xmldom.Item(Chilnodes ,0))); Lv_City_Name := Xmldom.Getnodevalue(Xmldom.Getfirstchild(Xmldom.Item(Chilnodes ,1))); Lv_Zip_Code := Xmldom.Getnodevalue(Xmldom.Getfirstchild(Xmldom.Item(Chilnodes ,2))); Dbms_Output.Put('Ln_City_Id:' || Ln_City_Id); Dbms_Output.Put(',Lv_City_Name:' || Lv_City_Name); Dbms_Output.Put(',Lv_Zip_Code:' || Lv_Zip_Code); Dbms_Output.Put_Line(''); END LOOP; --释放文档对象 Xmldom.Freedocument(Xmldoc); --异常与错误处理 EXCEPTION WHEN OTHERS THEN Dbms_Output.Put_Line(SQLERRM); END;