I have an XML like this in a BLOB column:
<?xml version="1.0" encoding="UTF-8"?> <document xmlns="urn:xyzns"> <history> <Event> <year>1983</year> <Country> <Location>Lisbon</Location> <Type>Political</Type> </Country> </Event> <Event> <Country> <Location>USA</Location> <Type>Entertainment</Type> <year>2016</year> </Country> </Event> </history> </document>
As you can see the year can be either in the event level or at country level. There can be multiple events and multiple countries per event. This whole XML is stored in a BLOB column in Oracle. I need to extract the value of the year or better check if the year is 2000 and if so return the primary key of the row.
I used EXISTSNODE
to check if the year tag is present.
select pk from table where XMLType(blobdata, nls_charset_id('UTF8')).EXISTSNODE('/Document/history/Event[*]/year', 'xmlns="urn:xyzns"') = 1 and EXTRACTVALUE(XMLTYPE(blobdata, nls_charset_id('UTF8')), '/Document/history/Event[*]/year/text()', 'xmlns="urn:xyzns"') = '2000';
However this fails and the extractvalue
query returns multiple nodes, so I changed the parameter to '/Document/history/Event[1]/year/text()'
to check and it works. However this wouldnt be enough as it only checks the first event tag.
I looked at other questions here and one of the options was to use XMLTABLE since extractvalue is deprecated. I am having trouble understanding the parameters given inside the XMLTABLE. Could someone explain how to use XMLTABLE in this scenario? I should point out that the original datatype is BLOB and not CLOB. Thank you.
Advertisement
Answer
Use XMLTABLE
to get values for both locations and then use COALESCE
to show whichever is not NULL
:
SELECT COALESCE( year, country_year ) AS year, location, type FROM table_name t CROSS APPLY XMLTABLE( XMLNAMESPACES( DEFAULT 'urn:xyzns' ), '/document/history/Event' PASSING XMLTYPE(t.blobdata, nls_charset_id('UTF8')) COLUMNS year NUMBER(4,0) PATH './year', country_year NUMBER(4,0) PATH './Country/year', location VARCHAR2(200) PATH './Country/Location', type VARCHAR2(200) PATH './Country/Type' ) x
Which, for the sample data:
CREATE TABLE table_name ( blobdata BLOB ); INSERT INTO table_name VALUES ( UTL_RAW.CAST_TO_RAW( '<?xml version="1.0" encoding="UTF-8"?> <document xmlns="urn:xyzns"> <history> <Event> <year>1983</year> <Country> <Location>Lisbon</Location> <Type>Political</Type> </Country> </Event> <Event> <Country> <Location>USA</Location> <Type>Entertainment</Type> <year>2016</year> </Country> </Event> </history> </document>' ) );
Outputs:
YEAR | LOCATION | TYPE ---: | :------- | :------------ 1983 | Lisbon | Political 2016 | USA | Entertainment
db<>fiddle here