with the following query Im trying to Read MessageID and DocPurpose. but only Message ID is showing fine.... Can anyone tellme what Im missing? It will be apreciated
Declare #XmlData XML =
'<Envelope xmlns="http://schemas.microsoft.com/dynamics/2011/01/documents/Message">
<Header>
<MessageId>e96d3ee4-5cca-4b3e-be60-d1284a0fb02f</MessageId>
<Company>CompanyX</Company>
<Action>http://schemas.microsoft.com/dynamics/2008/01/services/ReturnOrderInService/create</Action>
<ConversationId>320034ab-f5ee-41b0-ba35-e0669c2bf1b8</ConversationId>
<RequestMessageId>e96d3ee4-5cca-4b3e-be60-d1284a0fb02f</RequestMessageId>
</Header>
<Body>
<MessageParts>
<ReturnOrderIn xmlns="http://schemas.microsoft.com/dynamics/2008/01/documents/ReturnOrderIn">
<DocPurpose xmlns="">Original</DocPurpose>
<SenderId xmlns="">Xcorp</SenderId>
<SalesTable class="entity" xmlns="">
<_DocumentHash>63cf8580-92fe-4b17-b15c-8e619eecf71f</_DocumentHash>
<CurrencyCode>USD</CurrencyCode>
<CustAccount>147854</CustAccount>
<LanguageId>en-us</LanguageId>
<Reservation>None</Reservation>
<ReturnDeadline>2014-10-10</ReturnDeadline>
<ReturnReasonCodeId>Reason</ReturnReasonCodeId>
<SalesName>Stores</SalesName>
<SalesLine class="entity">
<DefaultDimension>
<Values xmlns="http://schemas.microsoft.com/dynamics/2008/01/sharedtypes">
<Value>
<Name>Site</Name>
<Value>VN</Value>
</Value>
</Values>
</DefaultDimension>
<ExpectedRetQty>-5</ExpectedRetQty>
<ItemId>Else</ItemId>
<Name>Something</Name>
<PriceUnit>11.00</PriceUnit>
<SalesQty>-15.00</SalesQty>
</SalesLine>
</SalesTable>
</ReturnOrderIn>
</MessageParts>
</Body>
</Envelope>'
Declare #MessageId varchar(50)
;WITH XMLNAMESPACES('http://schemas.microsoft.com/dynamics/2011/01/documents/Message' As a,
'http://schemas.microsoft.com/dynamics/2008/01/documents/ReturnOrderIn' As b,
default 'http://schemas.microsoft.com/dynamics/2011/01/documents/Message')
Select #MessageId =MessageId from
(SELECT
t.c.value('a:MessageId[1]', 'varchar(50)') MessageId
FROM #XmlData.nodes('/Envelope/Header') AS t(c)) x
Declare #DocPurpose varchar(50)
;WITH XMLNAMESPACES('http://schemas.microsoft.com/dynamics/2011/01/documents/Message' As a,
'http://schemas.microsoft.com/dynamics/2008/01/documents/ReturnOrderIn' As b,
default 'http://schemas.microsoft.com/dynamics/2011/01/documents/Message')
Select #DocPurpose = DocPurpose from
(SELECT
t.d.value('b:DocPurpose[1]', 'varchar(50)') DocPurpose
FROM #XmlData.nodes('Envelope/body/MessageParts/b:ReturnOrderIn') AS t(d))z
Print 'MessageID>>>>>>' + #MessageId
Print #DocPurpose
<DocPurpose xmlns=""> node is in empty namespace, not the default namespace. Since we can't declare a prefix to map empty namespace URI, just don't declare a default in ;WITH XMLNAMESPACES block. Try this way :
Declare #DocPurpose varchar(50)
;WITH XMLNAMESPACES
('http://schemas.microsoft.com/dynamics/2011/01/documents/Message' As a,
'http://schemas.microsoft.com/dynamics/2008/01/documents/ReturnOrderIn' As b)
Select #DocPurpose = DocPurpose from
(
SELECT t.d.value('DocPurpose[1]', 'varchar(50)') DocPurpose
FROM #XmlData.nodes('a:Envelope/a:Body/a:MessageParts/b:ReturnOrderIn') AS t(d)
)z
Small thing but matter, you need uppercase B for Body.
Related
Can someone please help... I cannot seem to figure this out... I need to parse this using T-SQL. I have it saved as a file in the C:\Temp directory, named "OpenPos.XML". Any help would be very greatly appreciated. I need to be able to parse the XML and write it to a SQL table.
If I do an outer apply at all levels, it applies every PO # to every line instead of just for the lines related to that PO #.
XML File:
<?xml version="1.0" encoding="utf-8"?>
<acXML lang="en-us" xmlns="https://www.autocrib.net/acXMLSchema.xsd">
<Header>
<From>
<Company>Rolls Royce ATC (Indianapolis)</Company>
<Identity>rollsroyceatc-indianapolis</Identity>
<DatabaseName>AutoCribNet2</DatabaseName>
</From>
</Header>
<Request>
<OpenPurchaseOrderRequest ReqType="GET">
<PoNo>1716W</PoNo>
<ExternalPoNo />
<LineItems>
<Item>
<Line>1</Line>
<TagNo>1716</TagNo>
<VendorID>QMS</VendorID>
<ItemID>CARD BC6266</ItemID>
<ItemType>Expendable</ItemType>
<ItemRFID />
<Station>01</Station>
<Bin>0825-04-B-06</Bin>
<OrderQty>1</OrderQty>
<Received>1</Received>
<ReceivedBurn>0</ReceivedBurn>
<PackQty>1</PackQty>
<UnitCost>0.0000</UnitCost>
<UnitPrice>0.0000</UnitPrice>
<Lot />
<IsSpotBuy>False</IsSpotBuy>
<SpotTranCode>0</SpotTranCode>
<Inspect>False</Inspect>
<InspDate />
<InspOnHand>0</InspOnHand>
<InspBurn>0</InspBurn>
<OrderDate>01-13-2022</OrderDate>
<DueDate>01-25-2022</DueDate>
<PromiseDt>01-25-2022</PromiseDt>
<ReceiveDt />
<Department />
<Job />
<Machine />
<Reason />
<Part />
<Processed>False</Processed>
</Item>
</LineItems>
</OpenPurchaseOrderRequest>
<OpenPurchaseOrderRequest ReqType="GET">
SQL:
--Open POs
SELECT PO_X = CAST(BulkColumn AS xml)
INTO #PO
FROM OPENROWSET(BULK 'C:\AutoCrib WebServices\XML Files\ATC\OpenPOs.XML', SINGLE_CLOB) t
SELECT [Company] = p.PO_X.value('(//*:Header/*:From/*:Company)[1]', 'varchar(150)')
, [Identity] = f.value('(*:Identity)[1]', 'varchar(200)')
, [DatabaseNM] = f.value('(*:DatabaseName)[1]', 'varchar(50)')
, [PoNo] = r.value('(*:PoNo)[1]', 'varchar(10)')
, [ItemLine] = i.value('(*:Line)[1]', 'int')
, [ItemTagNo] = i.value('(*:TagNo)[1]', 'varchar(10)')
, [ItemVendorID] = i.value('(*:VendorID)[1]', 'varchar(100)')
, [ItemID] = i.value('(*:ItemID)[1]', 'varchar(30)')
, [ItemRFID] = i.value('(*:ItemRFID)[1]', 'varchar(50)')
, [ItemStation] = i.value('(*:Station)[1]', 'varchar(5)')
, [ItemBin] = i.value('(*:Bin)[1]', 'varchar(30)')
, [ItemOrderQty] = i.value('(*:OrderQty)[1]', 'int')
, [ItemReceived] = i.value('(*:Received)[1]', 'int')
, [ItemReceivedBurn] = i.value('(*:ReceivedBurn)[1]', 'int')
, [ItemPackQty] = i.value('(*:PackQty)[1]', 'int')
, [ItemUnitCost] = i.value('(*:UnitCost)[1]', 'money')
, [ItemUnitPrice] = i.value('(*:UnitPrice)[1]', 'money')
, [ItemOrderDate] = i.value('(*:OrderDate)[1]', 'datetime')
, [ItemDueDate] = i.value('(*:DueDate)[1]', 'datetime')
, [ItemPromiseDate] = i.value('(*:PromiseDt)[1]', 'datetime')
, [ItemReceiveDate] = i.value('(*:ReceiveDt)[1]', 'datetime')
, [ItemProcessed] = i.value('(*:Processed)[1]', 'varchar(10)')
FROM #PO p
OUTER APPLY p.PO_X.nodes('//*:Header/*:From') a(f)
OUTER APPLY p.PO_X.nodes('//*:Request/*:OpenPurchaseOrderRequest') c(r)
OUTER APPLY p.PO_X.nodes('//*:Request/*:OpenPurchaseOrderRequest/*:LineItems/*:Item') l(i)
DROP TABLE #PO
Start with loading the file. This uses OPENROWSET, but you might find BULK INSERT more flexible.
SELECT DepX = CAST(BulkColumn AS xml)
INTO #Departments
FROM OPENROWSET(BULK 'C:\Temp\Departments.XML', SINGLE_CLOB) t
--SINGLE_CLOB|SINGLE_NCLOB for Ascii vs Unicode
Now, we can query the xml
SELECT [From.Company] = d.DepX.value('(//*:Header/*:From/*:Company)[1]', 'varchar(99)')
/* Shorter paths if we OUTER APPLY the root we're interested in */
, [From.Company Shortcut] = f.value('(*:Company)[1]', 'varchar(99)')
FROM #Departments d
OUTER APPLY d.DepX.nodes('//*:Header/*:From') a(f)
Results
From.Company
From.Company Shortcut
Test Company (Indianapolis)
Test Company (Indianapolis)
For help with xml shredding, try Jacob Sebastian's SELECT * FROM XML
The output is helpful, but taking the time to go through and understand how it works is very educational.
This uses namespace wildcard *:
More complex xml might require WITH XMLNAMESPACE
I was finally able to figure it out. I was missing the namespace. Here's my SQL logic:
DECLARE #XML XML =
(SELECT *
FROM OPENROWSET(BULK 'C:\Temp\OpenPOs.XML', SINGLE_CLOB) t)
;WITH XMLNAMESPACES (DEFAULT 'https://www.autocrib.net/acXMLSchema.xsd')
SELECT A.evnt.value('(PoNo/text())[1]','varchar(10)') AS Event_DriverId
,B.rec.value('(Line/text())[1]','int') AS Record_RecordId
FROM #XML.nodes('/acXML/Request/OpenPurchaseOrderRequest') A(evnt)
OUTER APPLY A.evnt.nodes('LineItems/Item') B(rec);
Hi I have the following code in SQL that outputs xml between 2 tables. The output is 90% correct but if possible add to the output and then also remove some of the output text.
I am not sure if SQL has the ability to code a type of a element in the output. Please see the code below with the output. Currently if possible I would like to make 2 changes to my current output. The changes are list at the end of the port
DECLARE #ID_Rechnung int = 1978,
#XMLData xml;
WITH XMLNAMESPACES ('?xml version="1.0" encoding="UTF-8"?' as ext)
SELECT
#XMLData = xmldat.xmldataCol
FROM
(
SELECT (
SELECT
-- HIER XML Daten generieren
[InvoiceHeader].[InvoiceDate] AS 'invoice-date',
([InvoiceHeader].[InvoiceNumber]) AS 'invoice-number',
cast(replace([InvoiceHeader].[GrossValue],' ','') as decimal(18,2)) AS 'gross-total',
cast(replace([InvoiceHeader].[NetValue],' ','') as decimal(18,2)) AS 'amount-due',
[InvoiceHeader].[VatRate] AS 'tax-rate',
cast(replace([InvoiceHeader].[VatValue],' ','') as decimal(18,2)) AS 'tax-amount',
[ImagePath] AS 'image-scan-url',
[InvoiceType] AS 'document-type',
[LegalEntityVATNo] AS 'account-type/id',
[LegalEntityName] AS 'account-type/name',
[SupplierCode] as 'supplier/number',
[Currency] as 'currency/code',
(
SELECT rtrim([InvoiceLines].[LineNumber]) AS [order-line-num]
, [PONumber] as [po-number],
CAST([InvoiceLines].[UnitPrice] AS decimal(18,2)) AS Price ,
[Quantity] as quantity,
[TaxAmount] as [tax-amount],
[LineTotal] as [total],
[Decsription] as description
FROM [InvoiceLines] WHERE [InvoiceLines].[DOCID] = #id_Rechnung
FOR XML PATH('Invoice-line'), ROOT('invoice-lines'), TYPE
)
FROM [InvoiceHeader]
WHERE [InvoiceHeader].[DOCID] = #ID_Rechnung
FOR XML PATH(''), TYPE, ROOT('invoice-header')
) AS xmldataCol
) AS xmldat;
SELECT #XMLData
.query('<invoice-header>
{
for $x in /invoice-header/*[local-name()!="root"]
return $x,
for $x in /invoice-header/root/r
return <invoice-lines>/<invoice-line>{$x/*}</invoice-line></invoice-lines>
}
</invoice-header>');
Output:
<invoice-header>
<invoice-date>20180509</invoice-date>
<invoice-number>1075440</invoice-number>
<gross-total>1376.67</gross-total>
<amount-due>1197.10</amount-due>
<tax-rate>15.00%</tax-rate>
<tax-amount>179.57</tax-amount>
<image-scan-url>\\INTEL-SQL01\Attachment\2018-06-20\7e0dd165-81d6-445a-95d1-8aac686d44ed\f9a1179c-2a54-480e-b97a-ce6ac7327ae0.000</image-scan-url>
<account-type>
<id>4010112052</id>
<name>CONSOLIDATEDPOWERPROJECTS</name>
</account-type>
<supplier>
<number>12345</number>
</supplier>
<currency>
<code>ZAR</code>
</currency>
<invoice-lines xmlns:ext="?xml version="1.0" encoding="UTF-8"?">
<Invoice-line>
<order-line-num>4</order-line-num>
<po-number>120934861</po-number>
<Price>50.00</Price>
<quantity>1.000000</quantity>
<tax-amount>7.500000</tax-amount>
<total>50.00</total>
<description>Test1</description>
</Invoice-line>
<Invoice-line>
<order-line-num>2</order-line-num>
<po-number>120934861</po-number>
<Price>10.00</Price>
<quantity>2.000000</quantity>
<tax-amount>4.500000</tax-amount>
<total>20.00</total>
<description>Test2</description>
</Invoice-line>
</invoice-lines>
</invoice-header>
1.How do I get rid of the following xmlns:ext="?xml version="1.0" encoding="UTF-8&in the line: "<invoice-lines xmlns:ext="?xml version="1.0" encoding="UTF-8"?">"
How would I code "<tax-amount>7.500000</tax-amount> to get the output": "<tax-amount type="decimal">7.500000</tax-amount>"
Without a minimal reproducible example it is not possible to give you a full working answer.
(1) As #JeroenMostert already pointed out, the
'?xml version="1.0" encoding="UTF-8"?'
is an XML prolog declaration. Just delete the following line:
WITH XMLNAMESPACES ('?xml version="1.0" encoding="UTF-8"?' as ext)
(2) Here is a conceptual example how to add an attribute to an XML element. What is important here is a sequential order of adding, i.e. attribute shall be first, element itself is 2nd.
SQL
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, [tax-amount] VARCHAR(20));
INSERT INTO #tbl ([tax-amount]) VALUES
(N'7.500000'),
(N'18.000000');
SELECT
'decimal' AS [tax-amount/#type]
, [tax-amount]
FROM #tbl
FOR XML PATH('r'), TYPE, ROOT('root');
Output
<root>
<r>
<tax-amount type="decimal">7.500000</tax-amount>
</r>
<r>
<tax-amount type="decimal">18.000000</tax-amount>
</r>
</root>
In Microsoft SQL Server I have a row which uses JSON. Like this
[
{"id":"_Diagnose","value":
{"$type":"System.Collections.Generic.List`1[[x2.Data.DataAccess.Entity.Helper.XmlHelper.MedDokDiagnose, Data.DataAccess.Entity]], mscorlib","$values":
[{"$type":"x2.Data.DataAccess.Entity.Helper.XmlHelper.MedDokDiagnose, Data.DataAccess.Entity","Icd":"G12.8","IcdBeschreibung":"Sonstige spinale Muskelatrophien und verwandte Syndrome","IcdNotationskennzeichen":null,"Erlaeuterung":null,"Ausnahmetatbestand":null,"Sicherheit":"G","Seitenlokalisation":null,"AbgesetztAm":null,"Warnings":[],"IdKategorieBevorAbgesetzt":null,"TnmStatus":null},
{"$type":"x2.Data.DataAccess.Entity.Helper.XmlHelper.MedDokDiagnose, Data.DataAccess.Entity","Icd":"B15.9","IcdBeschreibung":"Virushepatitis A ohne Coma hepaticum","IcdNotationskennzeichen":null,"Erlaeuterung":null,"Ausnahmetatbestand":null,"Sicherheit":"G","Seitenlokalisation":"","AbgesetztAm":null,"Warnings":[],"IdKategorieBevorAbgesetzt":null,"TnmStatus":null}]}
}
]
I want the two Values of ICD.
I have a SQL Statement like this which is working fine:
SELECT
DetailXml.value('shortinfo[1]', 'nvarchar(100)') as Text,
(select test_value from openjson(formularVariablen)
with (test_id nvarchar(MAX) '$.id', test_value nvarchar(MAX) '$.value."$values"[0].Icd') where test_id = '_Diagnose') as ICD1,
(select test_value from openjson(formularVariablen)
with (test_id nvarchar(MAX) '$.id', test_value nvarchar(MAX) '$.value."$values"[1].Icd') where test_id = '_Diagnose') as ICD2
from MedDok CROSS APPLY Detail.nodes('meddokformular') as SqlXml(DetailXml)
LEFT JOIN MedDokFormularVariable ON MedDok.Id=MedDokFormularVariable.Id_MedDok
where exists
(select * from openjson((select formularVariablen from MedDokFormularVariable where id_meddok = MedDok.ID))
with (test_id varchar(100) '$.id', test_value varchar(100) '$.value'))
But the problem is that its possible that there can be 3 or more ICD Key-Value-Pairs. And I want them all. I tried so many ways but nothing worked.
Use cross apply to list of values. Like this:
select
*
from OPENJSON(
'
[
{"id":"_Diagnose","value":
{"$type":"System.Collections.Generic.List`1[[x2.Data.DataAccess.Entity.Helper.XmlHelper.MedDokDiagnose, Data.DataAccess.Entity]], mscorlib","$values":
[{"$type":"x2.Data.DataAccess.Entity.Helper.XmlHelper.MedDokDiagnose, Data.DataAccess.Entity","Icd":"G12.8","IcdBeschreibung":"Sonstige spinale Muskelatrophien und verwandte Syndrome","IcdNotationskennzeichen":null,"Erlaeuterung":null,"Ausnahmetatbestand":null,"Sicherheit":"G","Seitenlokalisation":null,"AbgesetztAm":null,"Warnings":[],"IdKategorieBevorAbgesetzt":null,"TnmStatus":null},
{"$type":"x2.Data.DataAccess.Entity.Helper.XmlHelper.MedDokDiagnose, Data.DataAccess.Entity","Icd":"B15.9","IcdBeschreibung":"Virushepatitis A ohne Coma hepaticum","IcdNotationskennzeichen":null,"Erlaeuterung":null,"Ausnahmetatbestand":null,"Sicherheit":"G","Seitenlokalisation":"","AbgesetztAm":null,"Warnings":[],"IdKategorieBevorAbgesetzt":null,"TnmStatus":null}]}
}
]
')
with
(
[id] nvarchar(max),
[values] nvarchar(max) '$.value."$values"' AS JSON
) as a
CROSS APPLY OPENJSON([values])
WITH(
[Icd] nvarchar(max),
[IcdBeschreibung] nvarchar(max)
/* etc... */
) as b
dont have a sql2016. But made the code to work on XML.
DECLARE #myDoc XML;
SET #myDoc = '<id>_Diagnose</id>
<value>
<type>System.Collections.Generic.List`1[[x2.Data.DataAccess.Entity.Helper.XmlHelper.MedDokDiagnose, Data.DataAccess.Entity]], mscorlib</type>
<values>
<type>x2.Data.DataAccess.Entity.Helper.XmlHelper.MedDokDiagnose, Data.DataAccess.Entity</type>
<Icd>G12.8</Icd>
<IcdBeschreibung>Sonstige spinale Muskelatrophien und verwandte Syndrome</IcdBeschreibung>
<IcdNotationskennzeichen />
<Erlaeuterung />
<Ausnahmetatbestand />
<Sicherheit>G</Sicherheit>
<Seitenlokalisation />
<AbgesetztAm />
<IdKategorieBevorAbgesetzt />
<TnmStatus />
</values>
<values>
<type>x2.Data.DataAccess.Entity.Helper.XmlHelper.MedDokDiagnose, Data.DataAccess.Entity</type>
<Icd>B15.9</Icd>
<IcdBeschreibung>Virushepatitis A ohne Coma hepaticum</IcdBeschreibung>
<IcdNotationskennzeichen />
<Erlaeuterung />
<Ausnahmetatbestand />
<Sicherheit>G</Sicherheit>
<Seitenlokalisation></Seitenlokalisation>
<AbgesetztAm />
<IdKategorieBevorAbgesetzt />
<TnmStatus />
</values>
</value>
';
SELECT #myDoc;
-- BUILD XML
DECLARE #x XML;
SELECT #x =
(
SELECT #myDoc.value('(/id)[1]', 'varchar(50)') AS ID,
#myDoc.query('
for $a in //values
return <address
Icd="{$a/Icd}"
IcdBeschreibung="{$a/IcdBeschreibung}"
/>
') FOR XML RAW
);
SELECT [Name] = T.Item.value('../#ID', 'varchar(20)'),
street = T.Item.value('#Icd', 'varchar(20)'),
city = T.Item.value('#IcdBeschreibung', 'varchar(20)')
FROM #x.nodes('//row/address') AS T(Item);
I have a SOAP response with below structure and need to get the all the values for the below tags 1. result , documentNumber , costElementCode .
This is my XML sample :
DECLARE #myXML XML = '<commitmentsResponse xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<result xmlns="http://response.cim.its.test.edu.au/">SUCCESS</result>
<value>
<documentNumber xmlns="http://finance.cim.its.test.edu.au/">123456789</documentNumber>
<commitmentLine>
<lineNumber>2</lineNumber>
<costElementCode>costElementCode</costElementCode>
<internalOrderNumber>1000002</internalOrderNumber>
<costCentreCode>9999</costCentreCode>
<wbsCode>3000</wbsCode>
<lineDescription>2 packets of pencils</lineDescription>
<accountNumber>100000</accountNumber>
<itemAmount>105.5</itemAmount>
<fundsDueDate>2015-06-15</fundsDueDate>
</commitmentLine>
<commitmentLine xmlns="http://finance.cim.its.test.edu.au/">
<lineNumber>2</lineNumber>
<costElementCode>costElementCode</costElementCode>
<internalOrderNumber>1000002</internalOrderNumber>
<costCentreCode>9999</costCentreCode>
<wbsCode>3000</wbsCode>
<lineDescription>2 packets of pencils</lineDescription>
<accountNumber>100000</accountNumber>
<itemAmount>105.5</itemAmount>
<fundsDueDate>2015-06-15</fundsDueDate>
</commitmentLine>
</value>
<value>
<documentNumber xmlns="http://finance.cim.its.test.edu.au/">12345</documentNumber>
<commitmentLine>
<lineNumber>2</lineNumber>
<costElementCode>costElementCode</costElementCode>
<internalOrderNumber>1000002</internalOrderNumber>
<costCentreCode>9999</costCentreCode>
<wbsCode>3000</wbsCode>
<lineDescription>2 packets of pencils</lineDescription>
<accountNumber>100000</accountNumber>
<itemAmount>105.5</itemAmount>
<fundsDueDate>2015-06-15</fundsDueDate>
</commitmentLine>
<commitmentLine xmlns="http://finance.cim.its.test.edu.au/">
<lineNumber>2</lineNumber>
<costElementCode>costElementCode</costElementCode>
<internalOrderNumber>1000002</internalOrderNumber>
<costCentreCode>9999</costCentreCode>
<wbsCode>3000</wbsCode>
<lineDescription>2 packets of pencils</lineDescription>
<accountNumber>100000</accountNumber>
<itemAmount>105.5</itemAmount>
<fundsDueDate>2015-06-15</fundsDueDate>
</commitmentLine>
</value>
</commitmentsResponse>'
I have tried using the below but only get the first value and not all nodes :
DECLARE #DocumentNumber INT
;WITH XMLNAMESPACES (N'http://finance.cim.its.test.edu.au/' as DYN)
SELECT #DocumentNumber = c.value('(DYN:documentNumber)[1]', 'INT')
FROM #myXML.nodes('/commitmentsResponse/value') t(c)
DECLARE #Result VARCHAR(256)
;WITH XMLNAMESPACES (N'http://response.cim.its.test.edu.au/' as DYN)
SELECT #Result = c.value('(DYN:result)[1]', 'VARCHAR(256)')
FROM #myXML.nodes('/commitmentsResponse') t(c)
DECLARE #CostElementCode VARCHAR(256)
SELECT #CostElementCode = c.value('(costElementCode)[1]', 'VARCHAR(256)')
FROM #myXML.nodes('/commitmentsResponse/value/commitmentLine') t(c)
SELECT #Result
SELECT #DocumentNumber
SELECT #CostElementCode
You can use OUTER APPLY to shred XML data type into multiple rows. This is one example for extracting multiple costElementCodes value (implementing for the other elements should be trivial) :
SELECT x.value('.[1]', 'VARCHAR(256)') as costElementCode
FROM #myXML.nodes('/commitmentsResponse/value/commitmentLine') t(c)
OUTER APPLY t.c.nodes('costElementCode') cec(x)
I am trying to build a query that would return more or less complex XML structure. This is expected output I would like to have:
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action s:mustUnderstand="1">http://tempuri.org/IGeocodeService/HereRouteMatchExtension</a:Action>
<a:MessageID>urn:uuid: some_messageID</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">ServiceURL</a:To>
</s:Header>
<s:Body>
<HereRouteMatchExtension xmlns="http://tempuri.org/">
<vehicleTrace xmlns:b="http://schemas.datacontract.org/2004/07/FMCommonTypes.WCF" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<s:Latitude>2</s:Latitude>
<s:Longitude>2</s:Longitude>
<s:PositionGuid>577AF773-C7A8-4D65-82DA-37A15CC7611D</s:PositionGuid>
</vehicleTrace>
</HereRouteMatchExtension>
</s:Body>
</s:Envelope>
I am using following code:
CREATE TABLE #test
(
Latitude INT,
Longitude INT,
PositionGuid UNIQUEIDENTIFIER
)
INSERT INTO #test VALUES (1,1,NEWID())
INSERT INTO #test VALUES (2,2,NEWID())
WITH XMLNAMESPACES ('http://www.w3.org/2003/05/soap-envelope' AS s, 'http://www.w3.org/2005/08/addressing' AS a)
SELECT
( SELECT '1' AS [a:Action/#mustUnderstand],
'http://tempuri.org/IGeocodeService/HereRouteMatchExtension' AS [a:Action]
FOR XML PATH (''), TYPE
),
'urn:uuid: some_messageID' AS 'a:MessageID',
( SELECT 'http://www.w3.org/2005/08/addressing/anonymous' AS [a:Address]
FOR XML PATH ('a:ReplyTo'), TYPE
),
( SELECT '1' AS [a:To/#mustUnderstand],
'ServiceURL' AS [a:To]
FOR XML PATH (''), TYPE
),
( SELECT '1' AS [a:Action/#mustUnderstand]
FOR XML PATH (''), TYPE
),
(SELECT Latitude AS 's:Latitude',
Longitude AS 's:Longitude',
PositionGuid AS 's:PositionGuid'
FROM #test
FOR XML PATH ('s:Body'), TYPE
)
FOR XML RAW ('s:Header'), ELEMENTS, ROOT('s:Envelope')
There are 2 problems in the code i generated:
1) reference URLS are in every sub-section and I would like to have just once;
2) Body tag is inside the header and it is supposed to go straight after it...
How can I achieve that? This is the result I am getting:
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope" mustUnderstand="1">http://tempuri.org/IGeocodeService/HereRouteMatchExtension</a:Action>
<a:MessageID>urn:uuid: some_messageID</a:MessageID>
<a:ReplyTo xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope" mustUnderstand="1">ServiceURL</a:To>
<a:Action xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope" mustUnderstand="1" />
<s:Body xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Latitude>1</s:Latitude>
<s:Longitude>1</s:Longitude>
<s:PositionGuid>34BD8E91-8567-4D58-A18E-61C3FBBF5C8F</s:PositionGuid>
</s:Body>
</s:Header>
</s:Envelope>
Try that
DECLARE #test TABLE
(
Latitude INT,
Longitude INT,
PositionGuid UNIQUEIDENTIFIER
)
INSERT INTO #test VALUES (1,1,NEWID());
INSERT INTO #test VALUES (2,2,NEWID());
WITH XMLNAMESPACES ('http://www.w3.org/2003/05/soap-envelope' AS s, 'http://www.w3.org/2005/08/addressing' AS a)
SELECT
1 AS [s:Envelope/s:Header/a:Action/#s:mustUnderstand],
'http://tempuri.org/IGeocodeService/HereRouteMatchExtension' AS [s:Envelope/s:Header/a:Action],
'urn:uuid: some_messageID' AS [s:Envelope/s:Header/a:MessageID],
'http://www.w3.org/2005/08/addressing/anonymous' [s:Envelope/s:Header/a:ReplyTo/a:Address],
1 as [s:Envelope/s:Header/To/#s:mustUnderstand],
'ServiceURL' as [s:Envelope/s:Header/To],
Latitude as [s:Envelope/s:Body/s:Latitude],
Longitude as [s:Envelope/s:Body/s:Longitude],
PositionGuid as [s:Envelope/s:Body/s:PositionGuid]
FROM #test
FOR XML PATH('')
This way you produce two Envelope elements one for each row of the #table.
Edit:
I could not find a way to remove extra namespaces from child elements when generated with TYPE in a subquery with FOR XML PATH.
I came up with this solution which does not fully satisfy me:
DECLARE #test TABLE
(
Latitude INT,
Longitude INT,
PositionGuid UNIQUEIDENTIFIER,
x xml
)
DECLARE #x xml =
'<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action s:mustUnderstand="1">http://tempuri.org/IGeocodeService/HereRouteMatchExtension</a:Action>
<a:MessageID>urn:uuid: some_messageID</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">ServiceURL</a:To>
</s:Header>
<s:Body>
<HereRouteMatchExtension xmlns="http://tempuri.org/">
<vehicleTrace xmlns:b="http://schemas.datacontract.org/2004/07/FMCommonTypes.WCF" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<s:Latitude>2</s:Latitude>
<s:Longitude>2</s:Longitude>
<s:PositionGuid>577AF773-C7A8-4D65-82DA-37A15CC7611D</s:PositionGuid>
</vehicleTrace>
</HereRouteMatchExtension>
</s:Body>
</s:Envelope>'
INSERT INTO #test VALUES (10,10,NEWID(),#x);
INSERT INTO #test VALUES (20,20,NEWID(),#x);
UPDATE #test
SET x.modify('declare namespace s="http://www.w3.org/2003/05/soap-envelope";declare default element namespace "http://tempuri.org/";
replace value of (/s:Envelope/s:Body/HereRouteMatchExtension/vehicleTrace/s:Latitude/text())[1] with sql:column("Latitude")')
UPDATE #test
SET x.modify('declare namespace s="http://www.w3.org/2003/05/soap-envelope";declare default element namespace "http://tempuri.org/";
replace value of (/s:Envelope/s:Body/HereRouteMatchExtension/vehicleTrace/s:Longitude/text())[1] with sql:column("Longitude")')
UPDATE #test
SET x.modify('declare namespace s="http://www.w3.org/2003/05/soap-envelope";declare default element namespace "http://tempuri.org/";
replace value of (/s:Envelope/s:Body/HereRouteMatchExtension/vehicleTrace/s:PositionGuid/text())[1] with sql:column("PositionGuid")')
SELECT * FROM #test
and all at once with an insert:
DECLARE #test TABLE
(
Latitude INT,
Longitude INT,
PositionGuid UNIQUEIDENTIFIER,
x xml
)
DECLARE #x xml =
'<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action s:mustUnderstand="1">http://tempuri.org/IGeocodeService/HereRouteMatchExtension</a:Action>
<a:MessageID>urn:uuid: some_messageID</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">ServiceURL</a:To>
</s:Header>
<s:Body>
<HereRouteMatchExtension xmlns="http://tempuri.org/">
</HereRouteMatchExtension>
</s:Body>
</s:Envelope>'
INSERT INTO #test VALUES (10,10,NEWID(),#x);
INSERT INTO #test VALUES (20,20,NEWID(),#x);
UPDATE #test
SET x.modify('declare namespace s="http://www.w3.org/2003/05/soap-envelope";declare default element namespace "http://tempuri.org/";
insert <vehicleTrace xmlns:b="http://schemas.datacontract.org/2004/07/FMCommonTypes.WCF" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><s:Latitude>{sql:column("Latitude")}</s:Latitude>
<s:Longitude>{sql:column("Longitude")}</s:Longitude>
<s:PositionGuid>{sql:column("PositionGuid")}</s:PositionGuid></vehicleTrace> into (/s:Envelope/s:Body/HereRouteMatchExtension)[1]')
SELECT * FROM #test