【问题标题】:XMLTable query returns no resultXMLTable 查询不返回结果
【发布时间】:2021-07-29 21:14:06
【问题描述】:

我对 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 对。

感谢收看!

【问题讨论】:

  • 您对 XML 格式有任何控制权并可以更改它,以便每个 cntr/cntr_status 对都包含在不同的 cntr_result 元素中?尝试获取每个 cntr 元素,然后获取以下兄弟元素是一件痛苦的事情,如果包装元素中每个元素都只有一个单例,这会简单得多。
  • 是的,对不起,我的错。我已经纠正了这个例子。这确实是结果返回给我的方式。

标签: sql xml oracle xml-namespaces oracle11gr2


【解决方案1】:

使用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",
         '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>'
)
  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 格式更新

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

SELECT x.*
FROM   table_name t
       CROSS JOIN
       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/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",
           '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(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",
           'http://www.w3.org/2001/XMLSchema' as "xsd",
           'http://www.w3.org/2001/XMLSchema-instance' as "xsi",
           DEFAULT 'http://service.xxx.com'
         ),
         '/cntr_statuses/cntr_result'
         PASSING x.cntr_statuses
         COLUMNS
           cntr        VARCHAR2(20) PATH 'cntr',
           cntr_status VARCHAR2(20) PATH 'cntr_status'
       ) c;

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

那么输出是:

STATUS CNTR CNTR_STATUS
SUCCESS 1234567890A SUCCESS
SUCCESS 1234567890B SUCCESS

sqlfiddle here

【讨论】:

  • 非常感谢!我知道我用 DEFAULT 尝试了各种咒语,但都没有奏效。您先生/女士,今天是我的英雄!
  • @DCookie 更新了一个更简单的版本,这可能会或可能不会工作,具体取决于您的 Oracle 的次要版本是否足够高以至于没有错误。
  • 谢谢,您展示的简化查询非常适合我的应用程序。我现在有一个 PL/SQL 包,它可以生成请求、发送请求并处理响应。我们在 11.2.0.4。再次感谢!
猜你喜欢
  • 1970-01-01
  • 2021-07-31
  • 2019-09-18
  • 2012-05-08
  • 2016-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多