问题描述
我对 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
然后得到第一个 cntr
和 cntr_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