Trying to extract a namespace value from an xmltype - sql

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.

Related

Snowflake Get value from XML column

I am working in Snowflake
I need a specific value from XML
SELECT data_xml,REGEXP_SUBSTR(data_xml,'<pinLessNetworkBin>(.*?)(</pinLessNetworkBin>)',3) as network
FROM "DW"."DB"."TABLE"
My results for now
<pinLessNetworkBin>STAR</pinLessNetworkBin>
I just need the value inside
Here the xml:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:FundingSource xmlns:ns0="www.url.com/be/example/payments/model/Concepts/FundingSource" Id="12887819260" extId="">
<id>3939</id>
<pinLessNetworkBin>STAR</pinLessNetworkBin>
</ns0:FundingSource>
How I can get that value?
Regards
the contents of an XML object is retrieved via GET(object, '$') thus for your regex result GET(parse_xml(network), '$') will get you the content. See GET
or you should really retrieve the pinLessNetworkBin via XMLGET:
SELECT data_xml,
XMLGET(parse_xml(data_xml), 'pinLessNetworkBin') as pinLessNetworkBin
FROM "DW"."DB"."TABLE"
parse_xml(data_xml)
which will give you the <pinLessNetworkBin>STAR</pinLessNetworkBin> thus you want to fetch the contents
SELECT data_xml,
get(XMLGET(parse_xml(data_xml), 'pinLessNetworkBin'), '$') as pinLessNetworkBin
FROM "DW"."DB"."TABLE"
parse_xml(data_xml)
should give you 'STAR'
see the PARSE_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

PostgresSQL xpath with namespaces

I would like to know how to use the xpath funtion in the following example:
The xml is inside a table called SR_DATA, field XMLDATA of type TEXT
The following is the structure of the xml document:
<?xml version="1.0" encoding="UTF-8"?>
<modulo modelCodeScheme="DocType" modelCodeSchemeVersion="01" modelCodeValue="TYPE_20a" modelCodeMeaning="SCREENING" group="groupname" type="format" xmlns="http://www.expr.com/2008/FMSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<AAAAA modelCodeScheme="MAM" modelCodeSchemeVersion="1" modelCodeValue="AN_MAM_6" modelCodeMeaning="Family1" tipodato="booleano">
<![CDATA[false]]>
</AAAAA>
<BBBBB modelCodeScheme="MAM" modelCodeSchemeVersion="1" modelCodeValue="AN_MAM_8" modelCodeMeaning="Family2" tipodato="booleano">
<![CDATA[false]]>
</BBBBB>
</modulo>
Let's say I want to read the text about the element named AAAAA, so my query looks like this:
SELECT (xpath('/modulo/AAAAA/text()', XMLDATA::xml) AS status
FROM SR_DATA;
My query doesn't raise any error but the resultset is empty; I suppose I have to map the NAMESPACES but I need a hint on how to do it.
You need to specify namespaces in the xpath function. The node contains multiple text nodes; you could combine the nodes together using array_to_string function:
SELECT TRIM(BOTH FROM array_to_string(xpath('/x:modulo/x:AAAAA/text()', XMLDATA::xml, ARRAY[
ARRAY['x', 'http://www.expr.com/2008/FMSchema']
]), ''))
FROM SR_DATA
-- false
Demo on db<>fiddle

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
;