How to use XMLTABLE with multiple default namespaces - sql

My XML has multiple default name spaces, my below
<BusMsg>
<AppHdr xmlns="urn:iso:std:iso:20022:tech:xsd:head.001.001.01" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:head.001.001.01 General_head_001_001_01_20160503.xsd">
<CreDt>2017-06-29T05:32:11.147Z</CreDt>
<Prty>abc</Prty>
</AppHdr>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.05" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.05 SCT_pacs_008_001_05_20160503.xsd">
<FIToFICstmrCdtTrf>
<GrpHdr>
<MsgId>NATAAU33XXX2017062918789018AK12503</MsgId>
<CreDtTm>2017-06-29T05:32:11.147Z</CreDtTm>
<NbOfTxs>1</NbOfTxs>
<SttlmInf>
<SttlmMtd>abc</SttlmMtd>
<ClrSys>
<Cd>abc</Cd>
</ClrSys>
</SttlmInf>
<InstgAgt>
<FinInstnId>
<BICFI>abcdd</BICFI>
</FinInstnId>
</InstgAgt>
<InstdAgt>
<FinInstnId>
<BICFI>abcde</BICFI>
</FinInstnId>
</InstdAgt>
</GrpHdr>
</FIToFICstmrCdtTrf>
</Document>
</BusMsg>
I tried like below, but didnt work, its giving me null as output
SELECT f.PURPOSE
FROM tem_table,
XMLTABLE( xmlnamespaces(default 'urn:iso:std:iso:20022:tech:xsd:head.001.001.01 urn:iso:std:iso:20022:tech:xsd:pacs.008.001.05'), '/BusMsg/Document'
PASSING XMLTYPE(tem_table.SOURCE_MESSAGE_TEXT)
COLUMNS PURPOSE VARCHAR2(30) PATH 'FIToFICstmrCdtTrf/GrpHdr/MsgId') f
WHERE id = '5bf8356b2e63';
Any one idea having on how to handle this

Just because your XML document has different default namespaces in various elements, doesn't mean you have to use default namespaces to put them apart.
The namespace mappings you declare in the XMLTABLE function are only relevant int he XQuery expressions of this XMLTABLE call.
If you want to match the namespace urn:iso:std:iso:20022:tech:xsd:head.001.001.01 you have two options
declare it as default namespace and don't prefix the elements/attributes in the XQuery expressions.
assign it to a namespace prefix and also use that prefix in the XQuery expressions.
XMLTABLE(xmlnamespaces(default 'urn:iso:std:iso:20022:tech:xsd:head.001.001.01'
, 'urn:iso:std:iso:20022:tech:xsd:pacs.008.001.05' AS "n")
, '/BusMsg/Document'
PASSING XMLTYPE(tem_table.SOURCE_MESSAGE_TEXT)
COLUMNS PURPOSE VARCHAR2(30) PATH 'n:FIToFICstmrCdtTrf/n:GrpHdr/n:MsgId'
) f
I've assigned the NS ending in ".01" as default namespace and did not prefix the elements in the main QPath expression. I've also assigned the alias "n" to the other namespace, and also prefixed the elements from that namespace in the COLUMNS XQuery expression.
I might have done some typos and it might be better reversed to have less namespace prefixes.

Related

SQL get value from XML in tag, by tag value

I have the following XML:
<Main>
<ResultOutput>
<Name>TEST1</Name>
<Value>D028</Value>
</ResultOutput>
<ResultOutput>
<Name>TEST2</Name>
<Value>Accept</Value>
</ResultOutput>
<ResultOutput>
<Name>TEST3</Name>
<Value />
</ResultOutput>
</Main>
What I want is to get the value of the <value> tag in SQL.
Basically want to say get <value> where <Name> has the value of TEST1, as an example
This is what I have at the moment, but this depends on the position of the XML tag:
XMLResponse.value(Main/ResultOutput/Value)[5]', nvarchar(max)')
The best way to do this is not to put extra where .value clauses, but to do it directly in XQuery.
Use [nodename] to filter by a child node, you can even nest such predicates. text() gets you the inner text of the node:
XMLResponse.value('(/Main/ResultOutput[Name[text()="TEST1"]]/Value/text())[1]', 'nvarchar(max)')
Below is an example using the sample XML in your question. You'll need to extend this to add namespace declarations and the proper xpath expressions that may be present in your actual XML as your query attempt suggests.
SELECT ResultOutput.value('Value[1]', 'nvarchar(100)')
FROM #xml.nodes('Main/ResultOutput') AS Main(ResultOutput)
WHERE ResultOutput.value('Name[1]', 'nvarchar(100)') = N'TEST1';

How to generate namespaces in XML docs with Db2?

I want to generate the following xml doc in db2 and it has several namespaces:
<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
xmlns:ComIbmCompute.msgnode="ComIbmCompute.msgnode"
xmlns:ComIbmDatabase.msgnode="ComIbmDatabase.msgnode"
xmlns:ComIbmWSInput.msgnode="ComIbmWSInput.msgnode"
xmlns:ComIbmWSReply.msgnode="ComIbmWSReply.msgnode"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
xmlns:eflow="http://www.ibm.com/wbi/2005/eflow"
xmlns:utility="http://www.ibm.com/wbi/2005/eflow_utility"
nsURI="myflow/FIPRRCV.msgflow" nsPrefix="myflow_FIPRRCV.msgflow">
This does not work:
`SELECT XMLELEMENT(NAME "ecore:EPackage",
XMLNAMESPACES('eclipse.org/emf/2002/Ecore'; AS "ecore")) as "result"
FROM SYSIBM.SYSDUMMY1 WITH UR;`
How can I define multiple namespaces and use them in elements and attributes?
The function to use is called XMLNAMESPACES. The name suggests it is not a single, but multiple namespaceS are possible. :)
You can provide several namespace declarations in a comma-separated list. Only one namespace can be set as default namespace. Try something like this:
SELECT XMLELEMENT(NAME "ecore:EPackage",
XMLNAMESPACES('eclipse.org/emf/2002/Ecore' AS "ecore",
'example.com/foobar' as "foobar")) as "result"
FROM SYSIBM.SYSDUMMY1
If you need to add attributes with a prefix in their name, then just pass that combined string as attribute name to XMLATTRIBUTES. The xmi:version="2.0" in your example is "xmi:version" as name with a value of 2.0.

Configuring namespace for sp_xml_preparedocument

I have an RSS xml with this format:
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
<channel>
<title></title>
<link></link>
<description></description>
<language></language>
<lastBuildDate></lastBuildDate>
<generator></generator>
<docs></docs>
<managingEditor></managingEditor>
<webMaster></webMaster>
<ttl></ttl>
<item>
<title></title>
<link></link>
<description></description>
<guid isPermaLink="false"></guid>
<pubDate></pubDate>
<author></author>
<dc:date></dc:date>
<dc:publisher></dc:publisher>
<dc:language></dc:language>
</item>
<item>
<title></title>
<link></link>
<description></description>
<guid isPermaLink="false"></guid>
<pubDate></pubDate>
<author></author>
<dc:date></dc:date>
<dc:publisher></dc:publisher>
<dc:language></dc:language>
</item>
</channel>
</rss>
And I want to parse it with sp_xml_preparedocument in SQLServer.
My problem is the "namespce" field. There are three tags in each item which has namespace, and I don't know how to specify them.
I have tried this:
EXEC sp_xml_preparedocument #hDoc OUTPUT, #xmlContent,'<item xmlns:dc="http://purl.org/dc/elements/1.1/"/>'
but it just parse the first item and forget the rest!
Any idea?
The fact that you are only getting one row has nothing to do with the namespace. You have some error in your openxml query against #hDoc.
There might be reasons for you to still use openxml but until you show the query that is not working for you I will suggest you use the XML data type instead.
with xmlnamespaces('http://purl.org/dc/elements/1.1/' as dc)
select C.N.value('(title/text())[1]', 'nvarchar(100)') as channel_title,
I.N.value('(title/text())[1]', 'nvarchar(100)') as item_title,
I.N.value('(dc:publisher/text())[1]', 'nvarchar(100)') as publisher
from #XML.nodes('/rss/channel') as C(N)
cross apply C.N.nodes('item') as I(N);
SQL Fiddle
The namespace needs to be defined as a character type:
EXEC sp_xml_preparedocument #hDoc OUTPUT, #xmlContent,'<item xmlns:dc="http://purl.org/dc/elements/1.1/"/>'
[ xpath_namespaces ]
Specifies the namespace declarations that are used in row and column XPath expressions in OPENXML. xpath_namespaces is a text parameter: char, nchar, varchar, nvarchar, text, ntext or xml.
The default value is . xpath_namespaces provides the namespace URIs for the prefixes used in the XPath expressions in OPENXML by means of a well-formed XML document. xpath_namespaces declares the prefix that must be used to refer to the namespace urn:schemas-microsoft-com:xml-metaprop; this provides metadata about the parsed XML elements. Although you can redefine the namespace prefix for the metaproperty namespace by using this technique, this namespace is not lost. The prefix mp is still valid for urn:schemas-microsoft-com:xml-metaprop even if xpath_namespaces contains no such declaration.
http://msdn.microsoft.com/en-us/library/ms187367.aspx

Parsing SQL with bad xml namespace

Hi I have the following SQL to try and parse xml and extract the "OrderNumber". The problem i have is this xml (which i have no control over) has a wierd xml namespace. I changed it to abc.com just for this example, but its something else. Anyway, when that namepace is present, the T-SQL returns a null in the result. So it doesn't play nicely with the namespace. If I remove the namespace manually or doing a search and replace via T-SQL, it works just fine. I guess i can just do a search and replace but that solution just bothers me. Was wondering if anyone else nows a better way around this? And maybe an explanation of why it doesn't like namespaces? Would really appreciate some advice. Thanks!
Declare #Transmission xml
set #Transmission = '<Transmission>
<Requests>
<SubmitOrdersRequest>
<Orders>
<Order xmlns="http://www.abc.com">
<OrderNumber>123</OrderNumber>
</Order>
</Orders>
</SubmitOrdersRequest>
</Requests>
</Transmission>'
select #Transmission.value('(Transmission/Requests/SubmitOrdersRequest/Orders/Order/OrderNumber/text())[1]', 'varchar(100)')
Children nodes inherit the namespace of the parent, unless given a namespace themselves. you have to define namespaces using WITH XMLNAMESPACES, and properly qualify node names using them.
Declare #Transmission xml
set #Transmission = '<Transmission>
<Requests>
<SubmitOrdersRequest>
<Orders>
<Order xmlns="http://www.abc.com">
<OrderNumber>123</OrderNumber>
</Order>
</Orders>
</SubmitOrdersRequest>
</Requests>
</Transmission>';
with xmlnamespaces('http://www.abc.com' as ns1)
select #Transmission.value('(Transmission/Requests/SubmitOrdersRequest/Orders/ns1:Order/ns1:OrderNumber/text())[1]', 'varchar(100)')
Note: The reason for namespaces is that names are contextual things. Order can mean in your case a purchase but in another context it could mean display rack order. The namespace gives the name more uniqueness.

Replacing xml namespace prefixes in SQL Server with XQuery

I have an xml structure in an existing SQL Server 2005 database table with a particular namespace defined, I need to query out the XML and in the process, change the namespace prefix to become the default namespace. The old xml has the namespace defined on the root node and child nodes and I know how to replace the root easily enough, but not the child node's namespace.
Current Data:
<sg:Settings xmlns:sg="uri:mynamespace">
<sg:SomeData xmlns:sg="uri:mynamespace"/>
</sg:Settings>
Using the SQL:
WITH XMLNAMESPACES
('uri:mynamespace' as sg)
SELECT
settingsNode.query('<Settings xmlns="uri:mynamespace"> { sg:SomeData } </Settings> ')
FROM
SettingsTable CROSS APPLY
SettingsXml.nodes('/sg:Settings') T(settingsNode)
I can get the following:
<Settings xmlns="uri:mynamespace">
<sg:SomeData xmlns:sg="uri:mynamespace"/>
</Settings>
But I'm trying to get this:
<Settings xmlns="uri:mynamespace">
<SomeData/>
</Settings>
Is there a way to merge namespaces using SQL XQuery?
If you would like to replace it with space
update tbl_Archive set XML.modify('delete /*:Document/*:Volume[text()]/#xmlns:sg')