Extract Name and Value from XML Node in Oracle SQL - sql

I am trying to extract the Values based on Name via Oracle SQL query from the XML returned by a SOAP web service response, however it's resulting in errors. I could extract AdName, AdCat using this XMLTYPE method, but not the ones that's embedded further inside Results and AdSettings attributes. I must be wrong with the syntax I am using. Any help is appreciated.
SQL Query with XML Response:
WITH xmltest (id, data_xml) AS (
SELECT 1, XMLTYPE('<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<ResponseHeader xmlns="https://www.google.com/apis/ads/v202005">
<requestId>123456</requestId>
</ResponseHeader>
</soap:Header>
<soap:Body>
<getAdsResponse xmlns="https://www.google.com/apis/ads/v202005">
<getAdsResult>
<ResultReceived>1</ResultReceived>
<AdName>Target Comm. Systems</AdName>
<AdCat>COMMERCIAL</AdCat>
<SessionID>654321</SessionID>
<Results>
<Result><Name>ADId</Name><Value>2372</Value></Result>
<Result><Name>AdStatus</Name><Value>ACTIVE</Value></Result>
<Result><Name>targetWindow</Name><Value>TOP</Value></Result>
</Results>
<AdSettings>
<Setting><Name>fontFamily</Name><Value>DEFAULT</Value></Setting>
<Setting><Name>fontSize</Name><Value>9</Value></Setting>
<Setting><Name>adSenseEnabled</Name><Value>TRUE</Value></Setting>
<Setting><Name>adType</Name><Value>TEXT_AND_IMAGE</Value></Setting>
</AdSettings>
</getAdsResult>
</getAdsResponse>
</soap:Body>
</soap:Envelope>') FROM SYS.DUAL
)
SELECT x.Ad_Name,
x.Ad_Category,
x.Ad_ID,
x.Ad_Status,
x.AdSense_Enabled,
x.Ad_Type
FROM xmltest d,
XMLTABLE ( XMLNAMESPACES ( 'http://schemas.xmlsoap.org/soap/envelope/' AS "soap",
'https://www.google.com/apis/ads/v202005' AS "AdsNs2"
),
'/soap:Envelope/soap:Body/AdsNs2:getAdsResponse/AdsNs2:getAdsResult'
PASSING d.data_xml
COLUMNS Ad_Name VARCHAR2(50) PATH 'AdsNs2:AdName',
Ad_Category VARCHAR2(50) PATH 'AdsNs2:AdCat',
Ad_ID VARCHAR2(50) PATH 'AdsNs2/Results:Result[Name="ADId"]/Value',
Ad_Status VARCHAR2(50) PATH 'AdsNs2/Results:Result[Name="AdStatus"]/Value',
AdSense_Enabled VARCHAR2(50) PATH 'AdsNs2/Results:Result[Name="adSenseEnabled"]/Value',
Ad_Type VARCHAR2(50) PATH 'AdsNs2/Results:Result[Name="adType"]/Value'
) x;
Error:
ORA-19112: error raised during evaluation:
XVM-01081: [XPST0081] Invalid prefix
1 declare namespace soap="http://schemas.xmlsoap.org/soap/envelope/";declare
- ^
19112. 00000 - "error raised during evaluation: %s"
*Cause: The error function was called during evaluation of the XQuery expression.
*Action: Check the detailed error message for the possible causes.
Error at Line: 39 Column: 10

The last four columns XPath expressions were completely off. Here is how to do it correctly.
SQL
WITH xmltest (id, data_xml) AS (
SELECT 1, XMLTYPE('<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<ResponseHeader xmlns="https://www.google.com/apis/ads/v202005">
<requestId>123456</requestId>
</ResponseHeader>
</soap:Header>
<soap:Body>
<getAdsResponse xmlns="https://www.google.com/apis/ads/v202005">
<getAdsResult>
<ResultReceived>1</ResultReceived>
<AdName>Target Comm. Systems</AdName>
<AdCat>COMMERCIAL</AdCat>
<SessionID>654321</SessionID>
<Results>
<Result><Name>ADId</Name><Value>2372</Value></Result>
<Result><Name>AdStatus</Name><Value>ACTIVE</Value></Result>
<Result><Name>targetWindow</Name><Value>TOP</Value></Result>
</Results>
<AdSettings>
<Setting><Name>fontFamily</Name><Value>DEFAULT</Value></Setting>
<Setting><Name>fontSize</Name><Value>9</Value></Setting>
<Setting><Name>adSenseEnabled</Name><Value>TRUE</Value></Setting>
<Setting><Name>adType</Name><Value>TEXT_AND_IMAGE</Value></Setting>
</AdSettings>
</getAdsResult>
</getAdsResponse>
</soap:Body>
</soap:Envelope>') FROM SYS.DUAL
)
SELECT x.Ad_Name,
x.Ad_Category,
x.Ad_ID,
x.Ad_Status,
x.AdSense_Enabled,
x.Ad_Type
FROM xmltest d,
XMLTABLE ( XMLNAMESPACES ( 'http://schemas.xmlsoap.org/soap/envelope/' AS "soap",
'https://www.google.com/apis/ads/v202005' AS "AdsNs2"
),
'/soap:Envelope/soap:Body/AdsNs2:getAdsResponse/AdsNs2:getAdsResult'
PASSING d.data_xml
COLUMNS Ad_Name VARCHAR2(50) PATH 'AdsNs2:AdName',
Ad_Category VARCHAR2(50) PATH 'AdsNs2:AdCat',
Ad_ID VARCHAR2(50) PATH 'AdsNs2:Results/AdsNs2:Result[AdsNs2:Name="ADId"]/AdsNs2:Value',
Ad_Status VARCHAR2(50) PATH 'AdsNs2:Results/AdsNs2:Result[AdsNs2:Name="AdStatus"]/AdsNs2:Value',
AdSense_Enabled VARCHAR2(50) PATH 'AdsNs2:AdSettings/AdsNs2:Setting[AdsNs2:Name="adSenseEnabled"]/AdsNs2:Value',
Ad_Type VARCHAR2(50) PATH 'AdsNs2:AdSettings/AdsNs2:Setting[AdsNs2:Name="adType"]/AdsNs2:Value'
) x;

Related

How do i get the `ResponseDescription` value in Microsoft Sql?

So the column i'm querying has an XML data that looks like this
<soap:Envelope xmlns:soap="http://google.com/">
<soap:Body>
<ns2:response xmlns:ns2="http://stackoverflow.com/">
<trackingId>1375321435</trackingId>
<responseCode>202</responseCode>
<responseDescription>Request completed successfully</responseDescription>
<detail><?xml version="1.0" encoding="UTF-8" standalone="yes"?> <LoanProcessResponse> <ResponseCode>E4284</ResponseCode> <ResponseDescription>The minimum value date allowed for this account must be greater than [08-12-2022].: acctDisburseTranLA.valueDate</ResponseDescription> <status>FAILURE</status> </LoanProcessResponse></detail>
</ns2:response>
</soap:Body>
</soap:Envelope>
and my query looks like the below
WITH XMLNAMESPACES('http://google.com/' AS soap, 'http://stackoverflow.com/' AS ns2)
SELECT
timeSent,
accountNo,
isSuccessful,
try_convert(xml, responsePayload).query('/soap:Envelope/soap:Body/ns2:response/detail/LoanProcessResponse/ResponseDescription') AS response
from my_table
where accountNo = '000000008'
ORDER BY timesent desc;
Can you help me get the value of the <ResponseDescription> without the tag?
Please try the following solution.
It is better to use XML data type for the responsePayload column.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (id INT IDENTITY PRIMARY KEY, responsePayload NVARCHAR(MAX));
INSERT #tbl (responsePayload) VALUES
(N'<soap:Envelope xmlns:soap="http://google.com/">
<soap:Body>
<ns2:response xmlns:ns2="http://stackoverflow.com/">
<trackingId>1375321435</trackingId>
<responseCode>202</responseCode>
<responseDescription>Request completed successfully</responseDescription>
<detail><?xml version="1.0" encoding="UTF-8" standalone="yes"?> <LoanProcessResponse> <ResponseCode>E4284</ResponseCode> <ResponseDescription>The minimum value date allowed for this account must be greater than [08-12-2022].: acctDisburseTranLA.valueDate</ResponseDescription> <status>FAILURE</status> </LoanProcessResponse></detail>
</ns2:response>
</soap:Body>
</soap:Envelope>');
-- DDL and sample data population, end
;WITH XMLNAMESPACES('http://google.com/' AS soap, 'http://stackoverflow.com/' AS ns2)
SELECT ID
, responseDescription = TRY_CAST(responsePayload AS XML)
.value('(/soap:Envelope/soap:Body/ns2:response/responseDescription/text())[1]', 'VARCHAR(200)')
FROM #tbl;
Output
ID
responseDescription
1
Request completed successfully

Parsing XML with XMLTable n Oracle

I have one xml which holds customer and order details. I am parsing it using XMLTable. I think I am giving the correct XPath but I am getting no output.
Here is what I have tried. Hoping for assistance.
**DECLARE
l_raw_xml CLOB:= '<?xml version="1.0" encoding="utf-8"?>
<Root
xmlns="http://www.adventure-works.com">
<Customers>
<Customer CustomerID="GREAL">
<CompanyName>Great Lakes Food Market</CompanyName>
<ContactName>Howard Snyder</ContactName>
<ContactTitle>Marketing Manager</ContactTitle>
<Phone>(503) 555-7555</Phone>
<FullAddress>
<Address>2732 Baker Blvd.</Address>
<City>Eugene</City>
<Region>OR</Region>
<PostalCode>97403</PostalCode>
<Country>USA</Country>
</FullAddress>
</Customer>
</Customers>
<Orders>
<Order>
<CustomerID>LETSS</CustomerID>
<EmployeeID>6</EmployeeID>
<OrderDate>1997-11-10T00:00:00</OrderDate>
<RequiredDate>1997-12-08T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-11-21T00:00:00">
<ShipVia>2</ShipVia>
<Freight>45.97</Freight>
<ShipName>Let Stop N Shop</ShipName>
<ShipAddress>87 Polk St. Suite 5</ShipAddress>
<ShipCity>San Francisco</ShipCity>
<ShipRegion>CA</ShipRegion>
<ShipPostalCode>94117</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
</Orders>
</Root>';
l_xml_type XMLTYPE:=XMLTYPE.createXML(l_raw_xml);
cursor c_make_xml_object
is
SELECT x.*,
y.*
FROM XMLTABLE('/Root/Customers/Customer'
PASSING l_xml_type
COLUMNS
CustomerID VARCHAR2(255) PATH '#CustomerID',
CompanyName VARCHAR2(255) PATH 'CompanyName',
FullAddress XMLTYPE PATH 'FullAddress') x,
XMLTABLE('/FullAddress'
PASSING x.FullAddress
COLUMNS
Address VARCHAR2(255) PATH 'Address',
City VARCHAR2(255) PATH 'City') y ;
BEGIN
FOR rec IN c_make_xml_object
loop
DBMS_OUTPUT.PUT_LINE(rec.CustomerID);
DBMS_OUTPUT.PUT_LINE(rec.CompanyName);
END LOOP;
END;
/**
Do I have to account for the namespace? I had added namespace code but it did not work/
Change to this to include a default namespace:
FROM XMLTABLE(xmlnamespaces(default 'http://www.adventure-works.com'),
'/Root/Customers/Customer' ....
....
XMLTABLE(xmlnamespaces(default 'http://www.adventure-works.com'), '/FullAddress'
.....
Yes, a proper namespace definition is needed within the SQL query such as below :
SELECT x.*, y.*
FROM XML_TAB t,
XMLTABLE(XMLnamespaces('http://www.adventure-works.com' as "ns"),
'ns:Root/ns:Customers/ns:Customer'
PASSING t.xml_data
COLUMNS
CustomerID VARCHAR2(255) PATH '#CustomerID',
CompanyName VARCHAR2(255) PATH 'ns:CompanyName',
FullAddress XMLTYPE PATH 'ns:FullAddress'
) x,
XMLTABLE(XMLnamespaces('http://www.adventure-works.com' as "ns"),
'ns:FullAddress'
PASSING x.FullAddress
COLUMNS
Address VARCHAR2(255) PATH 'ns:Address',
City VARCHAR2(255) PATH 'ns:City') y ;
Demo with SQL
Demo with PL/SQL

Extracting values from XML column in Oracle

I have some data in an Oracle table which is stored in an XML-format string (column response in table WS_LOG).
I would like to extract data from each different node below <MedicalProcedureOutput>, but I'm having some difficulties in getting to each of the nodes. Can you spot what I'm doing wrong?
Here's what I'm trying (here trying to retrieve the value for the icpcID tag):
SELECT a.id,
t1.icpcID FROM
GH.WS_LOG a,
xmltable(
xmlnamespaces(
'http://schemas.xmlsoap.org/soap/envelope/' as "soap",
'http://www.w3.org/2001/XMLSchema' as "xsd",
'http://www.w3.org/2001/XMLSchema-instance' as "xsi"),
'/soap:Envelope/soap:Body/createBillingSubmissionForAFEBSGResponse/createBillingSubmissionForAFEBSGResult/proceduresList/MedicalProcedureOutput' passing xmltype(a.response) columns
icpcID varchar2(50) path 'ipcdId') t1
And here's some example data
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<createBillingSubmissionForAFEBSGResponse xmlns="urn:bcpcorp.net/ws/bsgFacets/FacetsBillingService">
<createBillingSubmissionForAFEBSGResult>
<status>0</status>
<outputMessage />
<statusElement />
<claimID>18E002021300</claimID>
<claimStatus>01</claimStatus>
<claimStatusReason>AGFP</claimStatusReason>
<totalChargeValue>35.0000</totalChargeValue>
<totalPayableValue>0.0000</totalPayableValue>
<paitentPaidvalue>17.5</paitentPaidvalue>
<totalDebitAmount>0</totalDebitAmount>
<proceduresList>
<MedicalProcedureOutput>
<ipcdId>011801</ipcdId>
<otherdisallowedAmountResponsibility>N</otherdisallowedAmountResponsibility>
</MedicalProcedureOutput>
</proceduresList>
</createBillingSubmissionForAFEBSGResult>
</createBillingSubmissionForAFEBSGResponse>
</soap:Body>
</soap:Envelope>
I would expect to be getting the value '011801'. Please note that multiple <MedicalProcedureOutput> nodes may occur, and they would be organized as follows:
<MedicalProcedureOutput>
<ipcdId>725013</ipcdId>
<otherdisallowedAmountResponsibility>N</otherdisallowedAmountResponsibility>
</MedicalProcedureOutput>
<MedicalProcedureOutput>
<ipcdId>725105</ipcdId>
<otherdisallowedAmountResponsibility>N</otherdisallowedAmountResponsibility>
</MedicalProcedureOutput>
You need to declare a default namespace for everything from within the body, since createBillingSubmissionForAFEBSGResponse has its own xmlns unnamed (therefore default) declaration which applies from that node onwards; so:
SELECT a.id,
t1.icpcID FROM
GH.WS_LOG a,
xmltable(
xmlnamespaces(
default 'urn:bcpcorp.net/ws/bsgFacets/FacetsBillingService',
'http://schemas.xmlsoap.org/soap/envelope/' as "soap",
'http://www.w3.org/2001/XMLSchema' as "xsd",
'http://www.w3.org/2001/XMLSchema-instance' as "xsi"
),
'/soap:Envelope/soap:Body/createBillingSubmissionForAFEBSGResponse/createBillingSubmissionForAFEBSGResult/proceduresList/MedicalProcedureOutput' passing xmltype(a.response) columns
icpcID varchar2(50) path 'ipcdId') t1
/
ID ICPCID
---------- --------------------------------------------------
1 011801
or with multiple nodes as you showed later int he question this will return:
ID ICPCID
---------- --------------------------------------------------
2 725013
2 725105
db<>fiddle
You should take a look into to solve it with the EXTRACTVALUE function, here You can find some information about it.

Reading XML Namespace using Oracle SQL

My XML Looks like below
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<wfm:Statement xmlns:wfm="http://example.org/sample/xsd/sampleStatement/2013/05" xmlns:wfmMerchant="http://www.eds.com/sample/xsd/wfmMerchant/2012/03"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<wfm:StatementParameters>
<wfmMerchant:HierarchyCd>012-12-002-107-050</wfmMerchant:HierarchyCd>
</wfm:StatementParameters>
<StatementAmount>27.140</StatementAmount>
</wfm:Statement>
I am trying to get the value of StatementAmount tag using Oracle query like below
select MS.MERCHANT,MS.CHAIN_HIERARCHY_CD,MS.CYCLE_DATE, X.StatementAmount
FROM CHAIN_STATMNT_HIST_XML MS
CROSS JOIN XMLTABLE(XMLNAMESPACES('http://example.org/sample/xsd/sampleStatement/2013/05' AS "wfm", 'http://www.eds.com/sample/xsd/wfmMerchant/2012/03' as wfmmerchant
default 'http://www.w3.org/2001/XMLSchema-instance')
,'/wfm:Statement/StatementAmount' passing xmltype(MS.XML_REPORT)
columns StatementAmount varchar(18) path '.')X
But, I am always getting NULL. I can able to successfully retrieve Hierarchy value from the XML which has namespace. But StatementAmount tag doesn't have any namespace and I have trouble retrieving it.
Can someone help with this issue ?
Your default namespace declaration seems to be causing the problem; without that (and ignoring wfmMerchant):
-- CTE for sample data
with CHAIN_STATMNT_HIST_XML (merchant, chain_hierarchy_cd, cycle_date, XML_REPORT) as (
select 1, 2, sysdate, '<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<wfm:Statement xmlns:wfm="http://example.org/sample/xsd/sampleStatement/2013/05" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<wfm:StatementParameters>
<!-- excluding this as namespace not provided -->
<!-- <wfmMerchant:HierarchyCd>012-12-002-107-050</wfmMerchant:HierarchyCd> -->
</wfm:StatementParameters>
<StatementAmount>27.140</StatementAmount>
</wfm:Statement>' from dual
)
-- actual query
select MS.MERCHANT,MS.CHAIN_HIERARCHY_CD,MS.CYCLE_DATE, X.StatementAmount
FROM CHAIN_STATMNT_HIST_XML MS
CROSS JOIN XMLTABLE(
XMLNAMESPACES('http://example.org/sample/xsd/sampleStatement/2013/05' AS "wfm"),
'/wfm:Statement/StatementAmount' passing xmltype(MS.XML_REPORT)
columns StatementAmount varchar(18) path '.'
) X
/
MERCHANT CHAIN_HIERARCHY_CD CYCLE_DATE STATEMENTAMOUNT
---------- ------------------ ---------- ------------------
1 2 2018-09-04 27.140
I'm not sure why you would use varchar2(18) as the datatype rather than number; and if there is only one statement amount per statement you could do:
select MS.MERCHANT,MS.CHAIN_HIERARCHY_CD,MS.CYCLE_DATE, X.StatementAmount
FROM CHAIN_STATMNT_HIST_XML MS
CROSS JOIN XMLTABLE(
XMLNAMESPACES('http://example.org/sample/xsd/sampleStatement/2013/05' AS "wfm"),
'/wfm:Statement' passing xmltype(MS.XML_REPORT)
columns StatementAmount number path 'StatementAmount'
) X

Extracting a node where xmlns is set to blank

I'm having difficulties extracting the value from certain nodes in an XML structure using XMLTABLE. Below query works perfectly when you remove the xmlns="" attribute from the SubListItem nodes. And as you can see, the XML already has a default namespace. I honestly have no clue how I can deal with this "blanking out" of the namespace on certain nodes like this.
For further clarification, the creation of this XML is not within my control and is provided by a third-party. I've also changed the names of the nodes and the content from the delivered files while preserving the structure of the XML.
SELECT f.airline, f.flightnumber, fl.gate
FROM xmltable(
xmlnamespaces(
default 'http://some/name.space',
'http://www.w3.org/2001/XMLSchema' as "xsd",
'http://www.w3.org/2001/XMLSchema-instance' as "xsi"
),
'Body/Flight'
passing xmltype(
'<?xml version="1.0" encoding="utf-16"?>
<Body xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://some/name.space">
<Sender>
<System>ConnectionManagement</System>
</Sender>
<Flight>
<Airline>ABC</Airline>
<Number>1234</Number>
<SubList>
<SubListItem xmlns="">
<Gate>X</Gate>
</SubListItem>
<SubListItem xmlns="">
<Gate>Y</Gate>
</SubListItem>
<SubListItem xmlns="">
<Gate>Z</Gate>
</SubListItem>
</SubList>
</Flight>
</Body>'
)
columns airline varchar2(100) path 'Airline'
, flightNumber VARCHAR2(5) path 'Number'
, subList XMLTYPE path 'SubList'
) f
, xmltable (
xmlnamespaces( default 'http://some/name.space'),
'/SubList/SubListItem'
passing f.subList
columns gate varchar2(5) path 'Gate'
) fl
;
How can I target the Gate node when the XML looks like this?
Leave the default namespace alone in the second XMLTable, and specify a named namespace for the path you do have:
...
, xmltable (
xmlnamespaces( 'http://some/name.space' as "ns"),
'/ns:SubList/SubListItem'
passing f.subList
columns gate varchar2(5) path 'Gate'
) fl
;
AIRLINE FLIGH GATE
---------- ----- -----
ABC 1234 X
ABC 1234 Y
ABC 1234 Z
The SubList still has to match that, but as the child nodes don't the default is incorrect the way you have it. If you remove the xmlns="" as you mentioned in the question then that inherits the namespace from its parent, so your default works. With that override to no-namespace you can't use a default.