Help needed to extract the data below from XML messages. I have table which contains the xml message in clob data type. I am trying using below query but it is not returning any data . I need to extract all the values from xml message.
<iORDERS:iORDERS xmlns:iORDERS="urn:iORDERS-abcdonline-com:Integration:v1">
<ORDER_NOTIFY>
<MESSAGE_DATETIME>2017-06-13T12:20:51+10:00</MESSAGE_DATETIME>
<MESSAGE_SEQ>1</MESSAGE_SEQ>
<MESSAGE_TYPE>PLACED</MESSAGE_TYPE>
<ORDER_HEAD>
<ORDER_ID>1111</ORDER_ID>
<DROP_SHIP_ORDER_NO></DROP_SHIP_ORDER_NO>
<CUSTOMER_ORDER_NO>22222</CUSTOMER_ORDER_NO>
<DISPATCH_LOCATION>
<SKU>2323234</SKU>
<UPC>4549432533626</UPC>
<REQUESTED_QTY>1</REQUESTED_QTY>
<DISPATCH_ASSIGNMENT>7777</DISPATCH_ASSIGNMENT>
<PROVIDER_ID>100</PROVIDER_ID>
<PKG_TYPE>SAT</PKG_TYPE>
</DISPATCH_LOCATION>
</ORDER_HEAD>
</ORDER_NOTIFY>
</iORDERS:iORDERS>
query :
select wor.batch_no,wor.web_service_no,x.*
from web_orders wo
cross join XMLTABLE (
XMLNAMESPACES(DEFAULT 'urn:iORDERS-abcdonline-com:Integration:v1'),
'iORDERS/ORDER_NOTIFY/ORDER_HEAD/DISPATCH_LOCATION'
passing xmltype(wo.xml_message)
columns
MESSAGE_TYPE varchar(120) path './../../../MESSAGE_TYPE') x;
You need to provide the named namespace identifier rather than a defealt, and your column path is going up one too many levels:
select wo.batch_no,wo.web_service_no,x.*
from web_orders wo
cross join XMLTABLE (
XMLNAMESPACES('urn:iORDERS-abcdonline-com:Integration:v1' as "iORDERS"),
'iORDERS:iORDERS/ORDER_NOTIFY/ORDER_HEAD/DISPATCH_LOCATION'
passing xmltype(wo.xml_message)
columns
MESSAGE_TYPE varchar(120) path './../../MESSAGE_TYPE') x;
BATCH_NO WEB_SERVICE_NO MESSAGE_TYPE
---------- -------------- ------------------------------------------------------------------------------------------------------------------------
1 2 PLACED
Presumably you're planning on getting for information that that from the XML, and/or expect to have multiple nodes; otherwise, to just get the message type you could simplify to:
select wo.batch_no,wo.web_service_no,x.*
from web_orders wo
cross join XMLTABLE (
XMLNAMESPACES('urn:iORDERS-abcdonline-com:Integration:v1' as "iORDERS"),
'iORDERS:iORDERS/ORDER_NOTIFY'
passing xmltype(wo.xml_message)
columns
MESSAGE_TYPE varchar(120) path 'MESSAGE_TYPE') x;
or even, with a single node:
select wo.batch_no,wo.web_service_no,XMLQuery(
'declare namespace iORDERS="urn:iORDERS-abcdonline-com:Integration:v1"; (: :)
iORDERS:iORDERS/ORDER_NOTIFY/MESSAGE_TYPE/text()'
passing xmltype(wo.xml_message)
returning content).getStringVal() as message_type
from web_orders wo;
Related
I got a sql from an Oracle table with a XMLTYPE column.
The Xml has a tag with a value '2' and in the same xml there is the list with value/label pairs like this:
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<characteristics>
<motor>
<fuel>2</fuel>
</motor>
</characteristics>
<ValuesList>
<CarValues>
<CarValue>
<value>1</value>
<label>Diesel</label>
</CarValue>
<CarValue>
<value>2</value>
<label>Unleaded petrol</label>
</CarValue>
</CarValues>
</ValuesList>
</Root>
With extract() or extractValue() functions it's easy to get the value for tag with any of these staments a, b
SELECT extract(t.xmlColumn, '//fuel/text()').getStringVal() a,
extractValue(t.xmlColumn, '//fuel') b
FROM Table t
The problem is I want to get the label text for value '2' from Valueslist 'Unleaded petrol'
I try to get that value with a XPATH expresion like this:
extractValue(t.xmlColumn, '//CarValue/label[../value=//fuel]')
The XPATH has been evaluated with Notepad XML Tools and it works, but there's no way to get any result. it's always null.
Any idea how to achive this? I don't know how to use XMLTABLE or any other solution to this case.
You need to include the /text() part in your attempt:
SELECT
extract(t.xmlColumn,'//fuel/text()').getStringVal() a
,extractValue(t.xmlColumn,'//fuel') b
,extractValue(t.xmlColumn, '//CarValue/label[../value=//fuel/text()]') c
FROM your_table t
A
B
C
2
2
Unleaded petrol
In your version you're trying to match a label with a value of the node <fuel>2</fuel>, not the text within than node, 2.
Both extract() and extractValue() are deprecated, so you could use XMLQuery instead:
SELECT
XMLQuery('//fuel/text()' passing xmlColumn returning content) a
,XMLQuery('//CarValue/label[../value=//fuel/text()]/text()' passing xmlColumn returning content) a
FROM your_table t
A
A
2
Unleaded petrol
Or with XMLTable();
SELECT x.a, x.b
FROM your_table t
CROSS APPLY XMLTable(
'/'
passing t.xmlColumn
columns a number path '//fuel',
b varchar2(30) path '//CarValue/label[../value=//fuel/text()]'
) x
A
B
2
Unleaded petrol
fiddle
If your version of Oracle isn't working with the node traversal using ../ then you could do it the hard way by getting the fuel value and all the id/label pairs with separate XMLTable calls, and then filtering those that match:
SELECT x1.fuel, x2.label
FROM your_table t
CROSS JOIN XMLTable(
'//fuel'
passing t.xmlColumn
columns fuel number path '.'
) x1
JOIN XMLTable(
'//CarValue'
passing t.xmlColumn
columns value number path 'value',
label varchar2(30) path 'label'
) x2 ON x2.value = x1.fuel
FUEL
LABEL
2
Unleaded petrol
fiddle
All solutions Alex Poole gave are accepted solutions for the question case title where "a value/label list within same XML" is present.
Just for information, in case "a value/label list is not present in the same XML", solution is create an auxiliary XMLTable with a XMLTYPE field and the value/label list XML in it.
SELECT x1.fuel, x2.labelFROM your_table t
CROSS JOIN XMLTable(
'//fuel'
passing t.xmlColumn
columns fuel number path '.'
) x1
LEFT JOIN XMLTable(
'//CarValue'
passing
(SELECT XMLTYPE('
<ValuesList>
<CarValues>
<CarValue>
<value>1</value>
<label>Diesel</label>
</CarValue>
<CarValue>
<value>2</value>
<label>Unleaded petrol</label>
</CarValue>
</CarValues>
</ValuesList>
') FROM dual)
columns value number path 'value',
label varchar2(30) path 'label'
) x2 ON x2.value = x1.fuel
I have the following SQL :
with q1 (Tdata) as (
SELECT XMLtype(transportdata, nls_charset_id('AL32UTF8'))
from bph_owner.paymentinterchange pint
where --PINT.INCOMING = 'T' and
PINT.TRANSPORTTIME >= to_date('2022-08-10', 'yyyy-mm-dd')
and pint.fileformat = 'pain.001.001.03'
)
--select XMLQuery('//*:GrpHdr/*:InitgPty/Nm/text()'
select tdata, XMLQuery('//*:GrpHdr/*:CtrlSum/text()'
passing Tdata
returning content).getstringval()
,
XMLQuery('//*:GrpHdr/*:MsgId/text()'
passing Tdata
returning content).getstringval()
from q1;
This works but for the InitgPty/Nm/ it doesn't - anybody know how I can extract this information?
Please be gentle as I don't work with XML much.
Thanks
Based on sample data from a previous question and other relating to this XML schema, it appears you just need to wildcard the namespace for Nm node, as well as its parents:
'//*:GrpHdr/*:InitgPty/*:Nm/text()'
so the query could become:
with q1 (Tdata) as (
SELECT XMLtype(transportdata, nls_charset_id('AL32UTF8'))
from paymentinterchange pint
where --PINT.INCOMING = 'T' and
PINT.TRANSPORTTIME >= to_date('2022-08-10', 'yyyy-mm-dd')
and pint.fileformat = 'pain.001.001.03'
)
select
XMLQuery('//*:GrpHdr/*:InitgPty/*:Nm/text()'
passing Tdata
returning content).getstringval() as nm
,
XMLQuery('//*:GrpHdr/*:CtrlSum/text()'
passing Tdata
returning content).getstringval() as ctrlsum
,
XMLQuery('//*:GrpHdr/*:MsgId/text()'
passing Tdata
returning content).getstringval() as msgig
from q1;
But if you're pulling multiple values out of the same document then it's simpler to use XMLTable rather than multiple XMLQuery calls:
select x.nm, x.ctrlsum, x.msgid
from paymentinterchange pint
cross apply XMLTable(
'//*:GrpHdr'
passing XMLtype(pint.transportdata, nls_charset_id('AL32UTF8'))
columns nm varchar2(50) path '*:InitgPty/*:Nm',
ctrlsum number path '*:CtrlSum',
msgid varchar2(50) path '*:MsgId'
) x
where pint.transporttime >= date '2022-08-10'
and pint.fileformat = 'pain.001.001.03';
db<>fiddle with data adapted from a previous question.
Before Oracle 12c you can use cross join instead of cross apply. I don't think it would make a difference in later versions either, that just seems to be my default now...
select x.nm, x.ctrlsum, x.msgid
from paymentinterchange pint
cross join XMLTable(
'//*:GrpHdr'
passing XMLtype(pint.transportdata, nls_charset_id('AL32UTF8'))
columns nm varchar2(50) path '//*:InitgPty/*:Nm',
ctrlsum number path '//*:CtrlSum',
msgid varchar2(50) path '//*:MsgId'
) x
where pint.transporttime >= date '2022-08-12'
and pint.fileformat = 'pain.001.001.03';
db<>fiddle showing it in 11.2.0.2, where it seems to need the // at the start of all the paths, including in the columns clause - those aren't needed in later versions, but here it returns nulls without them.
I have a query that I am running on AWS athena that should return all the filenames that are not contained in the second table. I am basically trying to find all the filename that are not in ejpos landing table.
The one table looks like this (item sales):
origin_file
run_id
/datarite/ejpos/8023/20220706/filename1
8035
/datarite/ejpos/8023/20220706/filename2
8035
/datarite/ejpos/8023/20220706/filename3
8035
The other table looks like this (ejpos_files_landing):
filename
filename1
filename2
filename3
filename4
They don't have the same number of rows, hence I am trying to find the file names that are in ejpos_pos_landing but not in item sales table.
I get this error when I run:
mismatched input 'from'. Expecting: ',', <expression>
The query is here:
SELECT trim("/datarite/ejpos/8023/20220706/" from "validated"."datarite_ejpos_itemsale" where
run_id = '8035') as origin_file,
FROM "validated"."datarite_ejpos_itemsale"
LEFT JOIN "landing"."ejpos_landing_files" ON "landing"."ejpos_landing_files".filename =
"validated"."datarite_ejpos_itemsale".origin_file
WHERE "landing"."ejpos_landing_files".filename IS NULL;
The expected result would be:
|filename4|
Because it is not in the other table
Can anyone assist?
There is a lot of wrong stuff in your query based on the example data and declared goals.
trim("/datarite/ejpos/8023/20220706/" from "validated"."datarite_ejpos_itemsale" where run_id = '8035') as origin_file is not a valid sql.
ON "landing"."ejpos_landing_files".filename = "validated"."datarite_ejpos_itemsale".origin_file will not work cause origin_file is prefixed. You can use strpos if there should be only one instance of filename in the origin_file.
your join and filtering condition are build to find items present in datarite_ejpos_itemsale and missing in ejpos_landing_files while you state the vise versa is needed.
the mentioned in the comments extra comma
Try next:
-- sample data
WITH item_sales(origin_file, run_id) AS (
VALUES ('/datarite/ejpos/8023/20220706/filename1', 8035),
('/datarite/ejpos/8023/20220706/filename2', 8035),
('/datarite/ejpos/8023/20220706/filename3', 8035),
('/datarite/ejpos/8023/20220706/filename4', 8036)
),
ejpos_files_landing(filename) as(
VALUES ('filename1'),
('filename2'),
('filename3'),
('filename4')
)
-- query
select filename
from ejpos_files_landing l
left outer join item_sales s -- reverse the join
on strpos(s.origin_file, l.filename) >= 1 -- assuming that filename should be present only one time in the string
and s.run_id = 8035 -- if you need to filter out run id
where s.origin_file is null
Output:
filename
filename4
Alternative approach you can try:
-- query
select filename
from ejpos_files_landing l
where filename not in (
select element_at(split(origin_file, '/'), -1) -- split by '/' and get last
from item_sales
where run_id = 8035
)
I'm trying to get the values of two attributes from table MVR_DTL in column VENDOR_XML. VENDOR_XML is of datatype clob and contains an xml that looks like this
<MVRCHPINFF_1.0>
<Routing ReplyToQMgr="PQ21" ReplyToQ="A4218QA.BIZTALK.REPLY.REPORT.PROD" CorelId="712393102361590" MsgType="8" Expiry="-1" MsgID="201904051632015"></Routing>
<MVRRecLoop>
<CLoop>
<CRec>
<C_MVRNumberAddr>ROMAN GENERAL</C_MVRNumberAddr>
</CRec>
<CRec>
<C_MVRNumberAddr>ROMAN ST</C_MVRNumberAddr>
</CRec>
<CRec>
<C_MVRNumberAddr>ROMAN CITY, ROME 111111</C_MVRNumberAddr>
</CRec>
</CLoop>
<HIJLoop>
<JRec>
<J_SVCDesc>MVR RECORD CLEAR</J_SVCDesc>
</JRec>
</HIJLoop>
</MVRRecLoop>
</MVRCHPINFF_1.0>
I tried running
SELECT c.J_SVCDesc, c.XMLDetails from MVR_DTL M,
XMLTABLE(
'string-join(/MVRCHPINFF_1.0/MVRRecLoop/CLoop/CRec/C_MVRNumberAddr, "|")'
passing XMLTYPE(M.VENDOR_XML)
columns XMLDetails varchar2(200) PATH '.',
J_SVCDesc varchar2(50) PATH './../../../HIJLoop/JRec/J_SVCDesc') c;
and i get this error
Error during Execute
S1000(19112)[Oracle][ODBC][Ora]ORA-19112: error raised during evaluation:
XVM-01020: [XPTY0020] The path step context item is not a node
I also tried
SELECT x1.J_SVCDesc, x2.XMLDetails from MVR_DTL M,
XMLTABLE('/MVRCHPINFF_1.0/MVRRecLoop'
passing XMLTYPE(M.VENDOR_XML)
columns
Address XMLTYPE path './CLoop/CRec/C_MVRNumberAddr',
J_SVCDesc varchar(50) PATH './HIJLoop/JRec/J_SVCDesc') x1
CROSS JOIN XMLTable(
'string-join(., "|")'
PASSING x1.Address
COLUMNS XMLDetails varchar2(200) PATH '.') x2;
but errored out with
Error during Execute
S1000(19279)[Oracle][ODBC][Ora]ORA-19279: XPTY0004 - XQuery dynamic type mismatch:
expected singleton sequence - got multi-item sequence
I'm trying to get
J_SVCDESC XMLDETAILS
MVR RECORD CLEAR ROMAN GENERAL|ROMAN ST|ROMAN CITY, ROME 111111
Could someone help me figure out what I'm missing.
You can move the string-join down to the columns clause:
select x.j_svcdesc, x.xmldetails
from mvr_dtl m
cross join xmltable (
'/MVRCHPINFF_1.0/MVRRecLoop'
passing xmltype(m.vendor_xml)
columns J_SVCDesc varchar2(50) path 'HIJLoop/JRec/J_SVCDesc',
xmldetails varchar2(200) path 'string-join(CLoop/CRec/C_MVRNumberAddr, "|")'
) x
Demo with your sample data in a CTE:
with mvr_dtl (vendor_xml) as (
select to_clob('<MVRCHPINFF_1.0>
<Routing ReplyToQMgr="PQ21" ReplyToQ="A4218QA.BIZTALK.REPLY.REPORT.PROD" CorelId="712393102361590" MsgType="8" Expiry="-1" MsgID="201904051632015"></Routing>
<MVRRecLoop>
<CLoop>
<CRec>
<C_MVRNumberAddr>ROMAN GENERAL</C_MVRNumberAddr>
</CRec>
<CRec>
<C_MVRNumberAddr>ROMAN ST</C_MVRNumberAddr>
</CRec>
<CRec>
<C_MVRNumberAddr>ROMAN CITY, ROME 111111</C_MVRNumberAddr>
</CRec>
</CLoop>
<HIJLoop>
<JRec>
<J_SVCDesc>MVR RECORD CLEAR</J_SVCDesc>
</JRec>
</HIJLoop>
</MVRRecLoop>
</MVRCHPINFF_1.0>')
from dual
)
select x.j_svcdesc, x.xmldetails
from mvr_dtl m
cross join xmltable (
'/MVRCHPINFF_1.0/MVRRecLoop'
passing xmltype(m.vendor_xml)
columns J_SVCDesc varchar2(50) path 'HIJLoop/JRec/J_SVCDesc',
xmldetails varchar2(200) path 'string-join(CLoop/CRec/C_MVRNumberAddr, "|")'
) x;
J_SVCDESC XMLDETAILS
-------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
MVR RECORD CLEAR ROMAN GENERAL|ROMAN ST|ROMAN CITY, ROME 111111
If the HIJLoop node name suggests there could be multiple JRec values too then you could concatenate those too:
columns J_SVCDesc varchar2(50) path 'string-join(HIJLoop/JRec/J_SVCDesc, "|")',
xmldetails varchar2(200) path 'string-join(CLoop/CRec/C_MVRNumberAddr, "|")'
which makes no difference to the output with the sample XML.
db<>fiddle
Incidentally, your second attempt sort of works; it doesn't error but doesn't get the right result either. The address you pass is an XML fragment with just sibling nodes, and the string-join only sees one value, consisting of the text() from those (I think... something like that). If you pass the CLoop down instead and expand the second XPath then it works:
select x1.j_svcdesc, x2.xmldetails
from mvr_dtl m
cross join xmltable (
'/MVRCHPINFF_1.0/MVRRecLoop'
passing xmltype(m.vendor_xml)
columns J_SVCDesc varchar(50) path 'HIJLoop/JRec/J_SVCDesc',
HIJLoop xmltype path 'CLoop'
) x1
cross join xmltable (
'string-join(CLoop/CRec/C_MVRNumberAddr, "|")'
passing x1.HIJLoop
columns xmldetails varchar2(200) path '.'
) x2;
db<>fiddle
But if you were actually getting "ORA-19279: XPTY0004 - XQuery dynamic type mismatch: expected singleton sequence - got multi-item sequence" then I suspect you have data that does actually have multiple JRec nodes; in which case see my second query above.
db<>fiddle showing that issue with this approach and my first query; and it working with my second query. So you probably need to use that:
select x.j_svcdesc, x.xmldetails
from mvr_dtl m
cross join xmltable (
'/MVRCHPINFF_1.0/MVRRecLoop'
passing xmltype(m.vendor_xml)
columns J_SVCDesc varchar2(50) path 'string-join(HIJLoop/JRec/J_SVCDesc, "|")',
xmldetails varchar2(200) path 'string-join(CLoop/CRec/C_MVRNumberAddr, "|")'
) x;
You might need to increase the returned column sizes, too.
I have the following query:
WITH XMLNAMESPACES ('CommonImport StudentRecordCount="1"
xsi:schemaLocation="http://collegeboard.org/CommonImport CommonImport.xsd"
xmlns="http://collegeboard.org/CommonImport"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' AS CommonImport)
SELECT B.award_year_token AS [StudentID/AwardYearToken]
,A.student_ssn AS [StudentID/SSN]
,A.last_name AS [StudentName/LastName]
,A.first_name AS [StudentName/FirstName]
,A.alternate_id AS [StudentName/AlternateID]
,'2807' AS [CustomStrings/CustomString/FieldID]
,C.processed_status AS [CustomStrings/CustomString/Value]
,'2506' AS [CustomDates/CustomDate/FieldID]
,CAST (C.date_processed AS DATE) AS [CustomDates/CustomDate/Value]
FROM [dbo].[student] A INNER JOIN [stu_award_year] B ON A.[student_token] = B.[student_token]
LEFT OUTER JOIN [dbo].[isir_convert_data] C ON A.[student_ssn] = C.[ssn] AND B.award_year_token = C.award_year_token
--LEFT OUTER JOIN [user_string] E ON B.[stu_award_year_token] = E.[stu_award_year_token]
--WHERE B.AWARD_YEAR_TOKEN = 2018 --For 18-19 year.
WHERE B.AWARD_YEAR_TOKEN = 2017 --For 17-18 year.
AND C.processed_status ='B'
AND C.date_processed = (SELECT MAX (X.date_processed)
FROM isir_convert_data X
WHERE C.ssn = X.ssn)
FOR XML PATH('Student'), ROOT('CommonImport')
The output is unusable due to the mishandling of the quotation marks. It looks like the following:
<CommonImport xmlns:CommonImport="CommonImport StudentRecordCount="1" xsi:schemaLocation="http://collegeboard.org/CommonImport CommonImport.xsd" xmlns="http://collegeboard.org/CommonImport" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"">
I am generating this via SQL Server. Can you offer any advice on how to properly create the XML Tag? And if I'm not properly using the XMLNAMESPACE function, please let me know. Thank you for considering.
You must distinguish between
the declaration of a namespace and
the usage of a namespace
It seems to me, that StudentRecordCount should be an attribute in the <CommonImport> node, same with schemaLocation. The second attribute is living within the xmlns:xsi-namespace.
You did not state the expected output, but my magic crystal ball showed me, that you might need this:
WITH XMLNAMESPACES (DEFAULT 'http://collegeboard.org/CommonImport'
,'http://www.w3.org/2001/XMLSchema-instance' AS xsi)
SELECT 1 AS [#StudentRecordCount]
,'http://collegeboard.org/CommonImport CommonImport.xsd' AS [#xsi:schemaLocation]
,'SomeOtherData' AS [Student/SomeElement]
FOR XML PATH('CommonImport');
the result
<CommonImport xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://collegeboard.org/CommonImport"
StudentRecordCount="1"
xsi:schemaLocation="http://collegeboard.org/CommonImport CommonImport.xsd">
<Student>
<SomeElement>SomeOtherData</SomeElement>
</Student>
</CommonImport>
If this does not help enough, please read about how to create a MCVE and provide sample data and expected output.
UPDATE 1
This is - roughly - what you need, but the namespaces are repeated. This is a known and annoying issue. Not wrong, the result is perfectly okay, but bloated.
WITH XMLNAMESPACES (DEFAULT 'http://collegeboard.org/CommonImport'
,'http://www.w3.org/2001/XMLSchema-instance' AS xsi)
,cte AS
(
SELECT object_id,name FROM sys.objects
)
SELECT COUNT(*) AS [#RecordCount]
,'http://collegeboard.org/CommonImport CommonImport.xsd' AS [#xsi:schemaLocation]
,(
SELECT *
FROM cte
FOR XML PATH('Object'),TYPE
)
FROM cte
FOR XML PATH('CommonImport');
UPDATE 2
An ugly workaround
WITH cte AS
(
SELECT object_id,name FROM sys.objects
)
SELECT
CAST(REPLACE(REPLACE(REPLACE(CAST(
(
SELECT COUNT(*) AS [#RecordCount]
,'http://collegeboard.org/CommonImport CommonImport.xsd' AS [#xsi_schemaLocation] --<-- "xsi:" is replaced with "xsi_"
,'http://collegeboard.org/CommonImport' AS [#_xmlns_] --<-- "xmlns" is not allowed
,'http://www.w3.org/2001/XMLSchema-instance' AS [#_xmlns_xsi] --<-- Same with "xmlns:xsi"
,(
SELECT *
FROM cte
FOR XML PATH('Object'),TYPE
)
FROM cte
FOR XML PATH('CommonImport'),TYPE) AS nvarchar(MAX)),'xsi_','xsi:'),'_xmlns_',' xmlns'),'xmlnsxsi','xmlns:xsi') AS XML);
Alternatively you might create the whole thing without namespaces at all and add the namespace declaration with string methods at the end.