Want fetch a XML node from Oracle table - sql

In the oracle table there is a column that stores XML below is the value:
<Header xmlns="http://load.xyx.gen/gen1"/>
<Body xmlns="http://load.xyx.gen/" xmlns:soapenv="http://load.xyx.gen/" xmlns:xsi="http://load.xyx.gen/instance" xmlns:SOAP-ENV="http://load.xyx.gen/" xmlns:SOAP-ENC="http://load.xyx.gen/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ns2:handleEmploye xmlns:ns2="http://load.xyx.gen/emp1">
<ns2:reisterEmp>
<ns4:empName xmlns:ns4="http://load.xyx.gen/empName1">Mirac</ns4:empName>
<ns4:empId xmlns:ns4="http://load.xyx.gen/empId1">12</ns4:empId>
<ns4:empDep xmlns:ns4="http://load.xyx.gen/empDep1">Finance</ns4:empDep>
</ns2:reisterEmp>
</ns2:handleEmploye>
</Body>
</soapenv:Envelope>
Now i am trying to fetch empId but getting below error:
ORA-31011: XML parsing failed ORA-19202: Error occurred in XML processing
I used ref. from this link
but it doesn't work for me.
SELECT XMLTYPE('<soapenv:Envelope xmlns:soapenv="http://load.xyx.gen/">
<Header xmlns="http://load.xyx.gen/gen1"/>
<Body xmlns="http://load.xyx.gen/" xmlns:soapenv="http://load.xyx.gen/" xmlns:xsi="http://load.xyx.gen/instance" xmlns:SOAP-ENV="http://load.xyx.gen/" xmlns:SOAP-ENC="http://load.xyx.gen/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ns2:handleEmploye xmlns:ns2="http://load.xyx.gen/emp1">
<ns2:reisterEmp>
<ns4:empName xmlns:ns4="http://load.xyx.gen/empName1">Mirac</ns4:empName>
<ns4:empId xmlns:ns4="http://load.xyx.gen/empId1">12</ns4:empId>
<ns4:empDep xmlns:ns4="http://load.xyx.gen/empDep1">Finance</ns4:empDep>
</ns2:reisterEmp>
</ns2:handleEmploye>
</Body>
</soapenv:Envelope>
').EXTRACT('//Body/ns2:handleEmploye/ns2:reisterEmp/ns4:empId/text()').getStringVal() result
FROM dual;
Can any one suggest?

You've mentioned ORA-31011 and ORA-19202, but with what you've shown those will be caused by LPX-00601:
ORA-31011: XML parsing failed
ORA-19202: Error occurred in XML processing
LPX-00601: Invalid token in: '//Body/ns2:handleEmploye/ns2:reisterEmp/ns4:empId/text()'
which is because your XML and XPath have namespace references (which look a bit confused in your modified XML), but you haven't included a namespace map in your extract() call:
SELECT XMLTYPE('...
').EXTRACT('//Body/ns2:handleEmploye/ns2:reisterEmp/ns4:empId/text()',
'xmlns="http://load.xyx.gen/" xmlns:ns2="http://load.xyx.gen/emp1" xmlns:ns4="http://load.xyx.gen/empId1"'
).getStringVal() result
FROM dual;
RESULT
12
You could use XMLQuery instead, and supply the namespaces within the XPath:
SELECT XMLQuery(
'declare namespace ns2="http://load.xyx.gen/emp1";
declare namespace ns4="http://load.xyx.gen/empId1";
declare default element namespace "http://load.xyx.gen/";
//Body/ns2:handleEmploye/ns2:reisterEmp/ns4:empId/text()'
PASSING XMLTYPE('...')
RETURNING CONTENT) AS result
FROM dual;
RESULT
12
and then convert the result to a number if you want.
Or if you actually plan to get all the values out you could use XMLTable, and supply the namespaces with XMLNamespaces; but because you define 'ns4' differently for each node (in this example anyway) you either need to give them unique names for the query:
SELECT empId, empName, empDep
FROM XMLTable(
XMLNamespaces(default 'http://load.xyx.gen/',
'http://load.xyx.gen/emp1' as "ns2",
'http://load.xyx.gen/empName1' as "ns4name",
'http://load.xyx.gen/empId1' as "ns4id",
'http://load.xyx.gen/empDep1' as "ns4dep"),
'//Body/ns2:handleEmploye/ns2:reisterEmp'
PASSING XMLTYPE('...')
COLUMNS
empId number PATH '//ns4id:empId',
empName varchar2(30) PATH '//ns4name:empName',
empDep varchar2(30) PATH '//ns4dep:empDep'
);
EMPID
EMPNAME
EMPDEP
12
Mirac
Finance
or you could wildcard them all:
SELECT empId, empName, empDep
FROM XMLTable(
XMLNamespaces(default 'http://load.xyx.gen/',
'http://load.xyx.gen/emp1' as "ns2",
'http://load.xyx.gen/empId1' as "ns4"),
'//Body/ns2:handleEmploye/ns2:reisterEmp'
PASSING XMLTYPE('...')
COLUMNS
empId number PATH '//*:empId',
empName varchar2(30) PATH '//*:empName',
empDep varchar2(30) PATH '//*:empDep'
);
EMPID
EMPNAME
EMPDEP
12
Mirac
Finance
db<>fiddle

Related

Trying to extract a namespace value from an xmltype

my BLOB (converted to XMLType) contains the following :
<?xml version="1.0" encoding="UTF-8"?><S2SCTScf:SCTScfBlkCredTrf xsi:schemaLocation="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf SCTScfBlkCredTrf.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:S2SCTScf="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf"><S2SCTScf:SndgInst>EBAPFRPA</S2SCTScf:SndgInst><S2SCTScf:RcvgInst>NWBKGB2X</S2SCTScf:RcvgInst><S2SCTScf:SrvcId>SCT</S2SCTScf:SrvcId><S2SCTScf:TstCode>P</S2SCTScf:TstCode><S2SCTScf:FType>SCF</S2SCTScf:FType><S2SCTScf:FileRef>NSCT220610000729</S2SCTScf:FileRef><S2SCTScf:RoutingInd>IND</S2SCTScf:RoutingInd><S2SCTScf:FileBusDt>2022-06-10</S2SCTScf:FileBusDt><S2SCTScf:FileCycleNo>11</S2SCTScf:FileCycleNo><S2SCTScf:FIToFICstmrCdtTrf xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02"><GrpHdr><MsgId>NSCT2206100007290000000000000000001</MsgId><CreDtTm>2022-06-10T09:52:54</CreDtTand
I wish to use SQL to extract the namespace value :
<S2SCTScf:FIToFICstmrCdtTrf xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02">
How would I do that - I tried XMLQuery but couldn't get it to work.
Many thanks
You can use FLOWR to delete the child elements and just return that single element:
SELECT XMLQUERY(
'declare namespace S2SCTScf="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf";
copy $e := /S2SCTScf:SCTScfBlkCredTrf/S2SCTScf:FIToFICstmrCdtTrf
modify (
for $i in $e/*
return delete node $i
)
return $e'
PASSING value RETURNING CONTENT
).getStringVal() AS xmlns_element
FROM table_name
Which, for the sample data:
CREATE TABLE table_name (value) AS
SELECT XMLTYPE('<?xml version="1.0" encoding="UTF-8"?>
<S2SCTScf:SCTScfBlkCredTrf xsi:schemaLocation="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf SCTScfBlkCredTrf.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:S2SCTScf="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf">
<S2SCTScf:SndgInst>EBAPFRPA</S2SCTScf:SndgInst>
<S2SCTScf:RcvgInst>NWBKGB2X</S2SCTScf:RcvgInst>
<S2SCTScf:SrvcId>SCT</S2SCTScf:SrvcId>
<S2SCTScf:TstCode>P</S2SCTScf:TstCode>
<S2SCTScf:FType>SCF</S2SCTScf:FType>
<S2SCTScf:FileRef>NSCT220610000729</S2SCTScf:FileRef>
<S2SCTScf:RoutingInd>IND</S2SCTScf:RoutingInd>
<S2SCTScf:FileBusDt>2022-06-10</S2SCTScf:FileBusDt>
<S2SCTScf:FileCycleNo>11</S2SCTScf:FileCycleNo>
<S2SCTScf:FIToFICstmrCdtTrf xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02">
<GrpHdr>
<MsgId>NSCT2206100007290000000000000000001</MsgId>
<CreDtTm>2022-06-10T09:52:54</CreDtTm>
</GrpHdr>
</S2SCTScf:FIToFICstmrCdtTrf>
</S2SCTScf:SCTScfBlkCredTrf>') FROM DUAL;
Outputs:
XMLNS_ELEMENT
<S2SCTScf:FIToFICstmrCdtTrf xmlns:S2SCTScf="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf" xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02"/>
db<>fiddle here
As this and the XML in your previous question both have the GrpHdr node, and you were trying to the MsgId from it then, you might simply be trying to get the namespace so you can pass it back into another XMLQuery call.
If that is the case then you could ignore the namespaces and use wildcards:
with q1 (Tdata) as (
SELECT XMLtype(transportdata, nls_charset_id('AL32UTF8')) from paymentinterchange
)
select XMLQuery('//*:GrpHdr/*:MsgId/text()'
passing Tdata
returning content).getstringval()
from q1
which would get the message ID from this XML or the previous example. I've changed the character set to AL32UTF8 to match this XML's UTF-8 declaration, which could be a problem if you have a mix of encodings in your data.
db<>fiddle with the old and new XML.

exporting xml value from CLOB data field in oracle using multiple namespace

I have a table which contains x number of records. One of the fields is a CLOB and contains XML with a particular field
Here is a very shortened version of the XML
<metadata xml:lang="en"
xmlns:gmd="http://www.isotc211.org/2005/gmd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gco="http://www.isotc211.org/2005/gco" xmlns:srv="http://www.isotc211.org/2005/srv" xmlns:gts="http://www.isotc211.org/2005/gts" xmlns:gml="http://www.opengis.net/gml" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<gmd:GEMINI_Metadata>
<gmd:fileIdentifier>
<gco:CharacterString>cf40a39a-0721-4fd4-84f3-adc28aee1158</gco:CharacterString>
</gmd:fileIdentifier>
<gmd:dateStamp>
<gco:Date>2019-01-16</gco:Date>
</gmd:dateStamp>
</gmd:GEMINI_Metadata>
</metadata>
What I would like to do is get characterstring value from the fileIdentifier tag using SQL
I have tried the following
select EXTRACT (XMLType (DOCUMENTATION), '//fileIdentifier//gco:CharacterString','xmlns:gmd="http://www.isotc211.org/2005/gmd"', 'xmlns:gco="http://www.isotc211.org/2005/gco"') as DOCUMENTATION from sde.gdb_items_vw where name = 'testTable'
i get the following
ORA-00939: too many arguments for function
If I try only specifying one tag and one namespace like this
select EXTRACT (XMLType (DOCUMENTATION), '//gmd:fileIdentifier','xmlns:gmd="http://www.isotc211.org/2005/gmd"') as DOCUMENTATION from sde.gdb_items_vw where name = 'testTable';
I get the following
DOCUMENTATION
--------------------------------------------------------------------------------
<gmd:fileIdentifier xmlns:gmd="http://www.isotc211.org/2005/gmd"><gco:CharacterS
So what is the correct way of getting a particular tag that has multiple namespaces within its tree?
The best method is to use XMLTABLE. Here you can easily specify the namespaces.
SELECT doc AS documentation
FROM sde.gdb_items_vw,
XMLTABLE( xmlnamespaces( 'http://www.isotc211.org/2005/gmd' AS "gmd",
'http://www.w3.org/2001/XMLSchema-instance' AS "xsi",
'http://www.isotc211.org/2005/gco' AS "gco",
'http://www.isotc211.org/2005/srv' AS "srv",
'http://www.isotc211.org/2005/gts' AS "gts",
'http://www.opengis.net/gml' AS "gml",
'http://www.w3.org/1999/xlink' AS "xlink",
'urn:schemas-microsoft-com:xslt' AS "msxsl"
),
'/metadata' PASSING XMLTYPE(documentation)
COLUMNS doc VARCHAR2(1000) PATH 'gmd:fileIdentifier/gco:CharacterString'
);
Result:
DOCUMENTATION
------------------------------------
cf40a39a-0721-4fd4-84f3-adc28aee1158

Selecting element from xml using xmlquery in Db2 (SQL/XML)

I have created table in Db2 like this:
create table xml_file(data xml not null)
This is the exact structure of xml:
<?xml version="1.0" encoding="UTF-8" ?>
<student id="20140021">
<name>Tom</name>
<surname>Johnson</surname>
<birth_date>"05/11/1995"</birth_date>
<birth_place>"Miami"</birth_place>
<points>9.45</points>
</student>
I want to select id, name, surname, and points for all students whose names are Ben and birth places are Chicago.
I wrote something like this:
select xmlquery('$DATA/student/data(#id)') as ID,
xmlquery('$DATA/student/name/text()') as NAME,
xmlquery('$DATA/student/surname/text()') as SURNAME,
xmlquery('$DATA/student/points/text()') as POINTS
from xml_file
where xmlexists('$DATA/student[birth_place = "Chicago"]')
and xmlexists('$DATA/student[name = "Ben"]');
All I got is this message: "FETCHED 0 RECORDS, 0 RECORDS SHOWN" (this is in IBM Data Studio).
Can someone tell me what did I do wrong?
Try this:
/*
WITH xml_file (data) AS
(
VALUES
XMLPARSE
(DOCUMENT '<?xml version="1.0" encoding="UTF-8" ?>
<student id="20140021">
<name>Tom</name>
<surname>Johnson</surname>
<birth_date>"05/11/1995"</birth_date>
<birth_place>"Miami"</birth_place>
<points>9.45</points>
</student>'
)
)
*/
SELECT X.*
FROM
xml_file V
, XMLTABLE
('$doc/student' PASSING V.data AS "doc"
COLUMNS
ID INT PATH '#id'
, NAME VARCHAR(20) PATH 'name'
, SURNAME VARCHAR(20) PATH 'surname'
, POINTS DEC(5, 2) PATH 'points'
) X
WHERE XMLEXISTS('$doc/student[birth_place = """Miami""" and name = "Tom"]' PASSING V.data AS "doc");
Try replacing your two where xmlexistss with one (this is used with your sample xml in the question, not your code):
where xmlexists('$DATA//student[birth_place/text()['Miami']][name/text()["Tom"]]');
or, two are required:
where xmlexists('$DATA/student[birth_place/text()['Miami']]')
and xmlexists('$DATA/student[name/text()["Tom"]]');
and see if either works.
The birth-place element contains double quotations marks which lead to an XPath evaluation error. To avoid this, replace where xmlexists('$DATA/student[birth_place = "Chicago"]') with one the following XPath expression :
XPath 1.0 friendly :
where xmlexists('$DATA/student/birth_place[substring(.,2,string-length(/student/birth_place)-2)="Chicago"]')
XPath 2.0 friendly :
where xmlexists('$DATA/student/birth_place[translate(.,codepoints-to-string(34),"")="Chicago"]')
XPath used to test on your sample data :
/student/birth_place[substring(.,2,string-length(/student/birth_place)-2)="Miami"]
/student/birth_place[translate(.,codepoints-to-string(34),"")="Miami"]

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

XML Parsing in Oracle

I am trying to parse an XML text. It is stored in a table t_testxml, in column xml_data which is CLOB type.
The xml looks like:
<?xml version="1.0" encoding="UTF-8"?>
<defaultmpftest:defaultmpftest xmlns:defaultmpftest="http://test.com"
test_id = "1231"
test_name = "name_test">
</mpftestdata:additionalLinkUrl xmlns:mpftestdata="http://test2.com"/>
</defaultmpftest:defaultmpftest>
How can I extract the values for test_id and test_name ?
I tried:
Select extract(xmltype.createxml(t.xml_data),'//defaultmpftest:defaultmpftest/#test_id').getStringVal() from t_testxml t;
But is not working. I get the following error:
ORA-31011: XML Parsing failed
LPX-00601: Invalid token in defaultmpftest:defaultmpftest/#test_id
Can you please give me some advices on this matter ?
Thank you !
The XML shown in the question is invalid, and would cause an "LPX-00231: invalid character" error if you passed it in to XMLType. So that isn't the string you're actually using. I'm assuming is a typo when posting the question, and you are actually getting the "LPX-00601: Invalid token" error you claimed. So I'll base this on that assumption, and on a string without that typo.
extract is deprecated; but even so, to use it here (with corrected raw XML) you need to specify the namespace with the optional third argument:
select extract(xmltype.createxml(t.xml_data),
'//defaultmpftest:defaultmpftest/#test_id',
'xmlns:defaultmpftest="http://test.com"').getStringVal()
from t_testxml t;
EXTRACT(XMLTYPE.CREATEXML(T.XML_DATA),'//DEFAULTMPFTEST:DEFAULTMPFTEST/#TEST_ID','XMLNS:DEFAULTMPFTEST="HTTP://TEST.COM"').GETSTRINGVAL()
-----------------------------------------------------------------------------------------------------------------------------------------
1231
Rather than using the deprecated function, you could use XMLQuery:
select xmlquery(
'declare namespace defaultmpftest="http://test.com"; (: :)
//defaultmpftest:defaultmpftest/#test_id'
passing xmltype.createxml(t.xml_data)
returning content).getStringVal()
from t_testxml t;
XMLQUERY('DECLARENAMESPACEDEFAULTMPFTEST="HTTP://TEST.COM";(::)//DEFAULTMPFTEST:DEFAULTMPFTEST/#TEST_ID'PASSINGXMLTYPE.CREATEXML(T.XML_DATA)RETURNINGCONTENT).GETSTRINGVAL()
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1231
You would need two XMLQuery clauses to get both values. I'd usually use XMLTable instead, shown here with the (fixed) XML-as-string provided via a CTE:
with t_testxml(xml_data) as (select '<?xml version="1.0" encoding="UTF-8"?>
<defaultmpftest:defaultmpftest xmlns:defaultmpftest="http://test.com"
test_id="1231"
test_name="name_test">
<mpftestdata:additionalLinkUrl xmlns:mpftestdata="http://test2.com"/>
</defaultmpftest:defaultmpftest>' from dual
)
select x.test_id, x.test_name
from t_testxml t
cross join xmltable(
xmlnamespaces('http://test.com' as "defaultmpftest"),
'//defaultmpftest:defaultmpftest'
passing xmltype(t.xml_data)
columns test_id number path '#test_id',
test_name varchar2(30) path '#test_name'
) x;
TEST_ID TEST_NAME
---------- ------------------------------
1231 name_test
Read more about using these functions.
The XML is not well-formed, try
<mpftestdata:additionalLinkUrl xmlns:mpftestdata="http://test2.com" />
or
<mpftestdata:additionalLinkUrl xmlns:mpftestdata="http://test2.com"></mpftestdata>
As Wernfried Domscheit correctly stated: Your XML is not well-formed. And for non-well-formed XMLs there's no way to extract information thereof in regular ways. Simply because regular ways are for XML; and your "XML" is not really an XML.
Let's try non-regular ways then...
with t_testxml as (
select q'{<?xml version="1.0" encoding="UTF-8"?>
<defaultmpftest:defaultmpftest xmlns:defaultmpftest="http://test.com"
test_id = "1231"
test_name = "name_test">
</mpftestdata:additionalLinkUrl xmlns:mpftestdata="http://test2.com"/>
</defaultmpftest:defaultmpftest>}' as xml_data
from dual
)
select xmlcast(xmlparse(content regexp_substr(T.xml_data, '<defaultmpftest:defaultmpftest[^>]+')||' />').extract('*/#test_id') as integer) as test_id
from t_testxml T
;