XMLTable 查询不返回结果

问题描述

我对 XML 只是暂时熟悉。我需要解析来自 SOAP 请求的响应。通过大量搜索,我开发了以下查询来尝试提取状态。最终,我想从响应中获取状态、cntr 和 cntr_status 字段。我的查询没有错误,但也没有结果。我犯了什么菜鸟错误?

SELECT *
  FROM XMLTABLE (
         XMLNAMESPACES('http://schemas.xmlsoap.org/soap/envelope/' as "soapenv",'http://www.w3.org/2001/XMLSchema' as "xsd",'http://www.w3.org/2001/XMLSchema-instance' as "xsi",'http://service.xxx.com/' AS "xxx"),'/soapenv:Envelope/soapenv:Body/xxx:sendDataResponse/xxx:sendDataReturn/xxx:result'
         PASSING XMLTYPE('<?xml version="1.0" encoding="UTF-8"?>' ||
                         '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" ' ||
                         '                  xmlns:xsd="http://www.w3.org/2001/XMLSchema" ' ||
                         '                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' ||
                         '  <soapenv:Body>' ||
                         '    <sendDataResponse xmlns="http://service.xxx.com">' ||
                         '      <sendDataReturn>' ||
                         '        <result>' ||
                         '          <build>Build 1</build>' ||
                         '          <status>SUCCESS</status>' ||
                         '          <cntr_statuses>' ||
                         '            <cntr_result>' ||
                         '              <cntr>1234567890A</cntr><cntr_status>SUCCESS</cntr_status>' ||
                         '            </cntr_result>' ||
                         '            <cntr_result>' ||
                         '              <cntr>1234567890B</cntr><cntr_status>SUCCESS</cntr_status>' ||
                         '            </cntr_result>' ||
                         '          </cntr_statuses>' ||
                         '        </result>' ||
                         '      </sendDataReturn>' ||
                         '    </sendDataResponse>' ||
                         '  </soapenv:Body>' ||
                         '</soapenv:Envelope>')
         COLUMNS status VARCHAR2(20) PATH 'xxx:status')  xmlstuff ;

来自服务的示例响应被硬编码到 XMLTYPE 函数中。

我尝试了任意数量的涉及 xxx 命名空间的查询字符串和列路径,都没有产生任何结果。

可能有数百个 cntr 和 cntr_status 对。

感谢您的关注!

解决方法

使用 DEFAULT 命名空间(因为您没有为 http://service.xxx.com 定义前缀)并删除对 xxx: 的引用似乎有效:

SELECT *
FROM XMLTABLE (
       XMLNAMESPACES(
         'http://schemas.xmlsoap.org/soap/envelope/' as "soapenv",'http://www.w3.org/2001/XMLSchema' as "xsd",'http://www.w3.org/2001/XMLSchema-instance' as "xsi",DEFAULT 'http://service.xxx.com'
       ),'/soapenv:Envelope/soapenv:Body/sendDataResponse/sendDataReturn/result'
       PASSING XMLTYPE(
         '<?xml version="1.0" encoding="UTF-8"?>' ||
         '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" ' ||
         '                  xmlns:xsd="http://www.w3.org/2001/XMLSchema" ' ||
         '                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' ||
         '  <soapenv:Body>' ||
         '    <sendDataResponse xmlns="http://service.xxx.com">' ||
         '      <sendDataReturn>' ||
         '        <result>' ||
         '          <build>Build 1</build>' ||
         '          <status>SUCCESS</status>' ||
         '          <cntr_statuses>' ||
         '            <cntr_result>' ||
         '              <cntr>1234567890A</cntr><cntr_status>SUCCESS</cntr_status>' ||
         '              <cntr>1234567890B</cntr><cntr_status>SUCCESS</cntr_status>' ||
         '            </cntr_result>' ||
         '          </cntr_statuses>' ||
         '        </result>' ||
         '      </sendDataReturn>' ||
         '    </sendDataResponse>' ||
         '  </soapenv:Body>' ||
         '</soapenv:Envelope>'
)

sqlfiddle here


然后得到第一个 cntrcntr_status

SELECT *
FROM XMLTABLE (
       XMLNAMESPACES(
         'http://schemas.xmlsoap.org/soap/envelope/' as "soapenv",'/soapenv:Envelope/soapenv:Body/sendDataResponse/sendDataReturn/result'
       PASSING XMLTYPE(
         '<?xml version="1.0" encoding="UTF-8"?>' ||
         '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" ' ||
         '                  xmlns:xsd="http://www.w3.org/2001/XMLSchema" ' ||
         '                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' ||
         '  <soapenv:Body>' ||
         '    <sendDataResponse xmlns="http://service.xxx.com">' ||
         '      <sendDataReturn>' ||
         '        <result>' ||
         '          <build>Build 1</build>' ||
         '          <status>SUCCESS</status>' ||
         '          <cntr_statuses>' ||
         '            <cntr_result>' ||
         '              <cntr>1234567890A</cntr><cntr_status>SUCCESS</cntr_status>' ||
         '              <cntr>1234567890B</cntr><cntr_status>SUCCESS</cntr_status>' ||
         '            </cntr_result>' ||
         '          </cntr_statuses>' ||
         '        </result>' ||
         '      </sendDataReturn>' ||
         '    </sendDataResponse>' ||
         '  </soapenv:Body>' ||
         '</soapenv:Envelope>'
)
  COLUMNS
    status      VARCHAR2(20) PATH 'status',cntr        VARCHAR2(20) PATH 'cntr_statuses/cntr_result/cntr[1]',cntr_status VARCHAR2(20) PATH 'cntr_statuses/cntr_result/cntr_status[1]'
)  xmlstuff;

sqlfiddle here


修改后的 XML 格式的更新

理想情况下,您应该能够在 '/soapenv:Envelope/soapenv:Body/sendDataResponse/sendDataReturn/result/cntr_status/cntr_result' 中使用 XPATH XMLTABLE,然后通过路径 status 获取 ./../../status;但是,我在尝试遍历父元素时不断获取 null 值,但找不到可行的解决方案。

SELECT x.*
FROM   table_name t
       CROSS JOIN
       XMLTABLE(
         XMLNAMESPACES(
           'http://schemas.xmlsoap.org/soap/envelope/' as "soapenv",DEFAULT 'http://service.xxx.com'
         ),'/soapenv:Envelope/soapenv:Body/sendDataResponse/sendDataReturn/result/cntr_statuses/cntr_result'
         PASSING XMLTYPE(t.xml)
         COLUMNS
           status      VARCHAR2(20) PATH './../../status',cntr        VARCHAR2(20)  PATH 'cntr',cntr_status VARCHAR2(20)  PATH 'cntr_status'
       ) x;

sqlfiddle here

根据 this comment,它将在 Oracle 11.2.0.4 中工作,但如果您在 Oracle 11.2.0.2 中尝试它,那么 status 将是 NULL(这是在 SQLFiddle 上看到的结果).


相反,对于多个 cntr_result 元素,您可以使用两个 XMLTABLE

SELECT x.status,c.cntr,c.cntr_status
FROM   table_name t
       CROSS JOIN
       XMLTABLE(
         XMLNAMESPACES(
           'http://schemas.xmlsoap.org/soap/envelope/' as "soapenv",'/soapenv:Envelope/soapenv:Body/sendDataResponse/sendDataReturn/result'
         PASSING XMLTYPE(t.xml)
         COLUMNS
           status        VARCHAR2(20) PATH 'status',cntr_statuses XMLTYPE      PATH 'cntr_statuses'
       ) x
       CROSS JOIN
       XMLTABLE(
         XMLNAMESPACES(
           'http://schemas.xmlsoap.org/soap/envelope/' as "soapenv",'/cntr_statuses/cntr_result'
         PASSING x.cntr_statuses
         COLUMNS
           cntr        VARCHAR2(20) PATH 'cntr',cntr_status VARCHAR2(20) PATH 'cntr_status'
       ) c;

假设您的数据位于 xml 表的 table_name 列中。

那么输出为:

状态 CNTR CNTR_STATUS
成功 1234567890A 成功
成功 1234567890B 成功

sqlfiddle here

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...