Query XML creating field names whithout knowing node names - sql-server

If I have a SQL SERVER 2012 table containing an XML field type. The records it could contain are as follows.
I have simplified my problem to the following.
Record 1:
ID_FIELD='nn1'
XML_FIELD=
<KNOWN_NAME_1>
<UNKNOWN_NAME1>Some value</UNKNOWN_NAME1>
<UNKNOWN_NAME2>Some value</UNKNOWN_NAME2>
... Maybe more ...
</KNOWN_NAME_1>
Record 2:
ID_FIELD='nn2'
XML_FIELD=
<KNOWN_NAME_2>
<UNKNOWN_NAME1>Some value</UNKNOWN_NAME1>
<UNKNOWN_NAME2>Some value</UNKNOWN_NAME2>
... Maybe more unknown fields ...
</KNOWN_NAME_2>
I want to output non xml:
UNKNOWN_NAME1 | UNKNOWN_NAME2 | ETC
-----------------------------------
Some Value Some value
For a known root value (i.e. KNOWN_NAME_1)
I.e. If I new the node values (which I don't) I could
SELECT
XMLData.Node.value('UNKNOWN_NAME1[1]', 'varchar(100)') ,
XMLData.Node.value('UNKNOWN_NAME2[1], 'varchar(100)')
FROM FooTable
CROSS APPLY MyXmlField.nodes('//KNOWN_NAME_1') XMLData(Node)
-- WHERE SOME ID value = 'NN1' (all XML records have a separate id)
All is good however I want to do this for all the nodes (unknown quantity) without knowing the node names. The root will only contain nodes it wont get any deeper.
Is this possible in SQL?
I have looked at this but I doubt I can get enough rights to implement it.
http://architectshack.com/ClrXmlShredder.ashx

If you don't know the column names in the output you have to use dynamic SQL:
-- Source table
declare #FooTable table
(
ID_FIELD char(3),
XML_FIELD xml
)
-- Sample data
insert into #FooTable values
('nn1', '<KNOWN_NAME_1>
<UNKNOWN_NAME1>Some value1</UNKNOWN_NAME1>
<UNKNOWN_NAME2>Some value2</UNKNOWN_NAME2>
</KNOWN_NAME_1>')
-- ID to look for
declare #ID char(3) = 'nn1'
-- Element name to look for
declare #KnownName varchar(100) = 'KNOWN_NAME_1'
-- Variable to hold the XML to process
declare #XML xml
-- Get the XML
select #XML = XML_FIELD
from #FooTable
where ID_FIELD = #ID
-- Variable for dynamic SQL
declare #SQL nvarchar(max)
-- Build the query
select #SQL = 'select '+stuff(
(
select ',T.N.value('''+T.N.value('local-name(.)', 'sysname')+'[1]'', ''varchar(max)'') as '+T.N.value('local-name(.)', 'sysname')
from #XML.nodes('/*[local-name(.)=sql:variable("#KnownName")]/*') as T(N)
for xml path(''), type
).value('.', 'nvarchar(max)'), 1, 1, '')+
' from #XML.nodes(''/*[local-name(.)=sql:variable("#KnownName")]'') as T(N)'
-- Execute the query
exec sp_executesql #SQL,
N'#XML xml, #KnownName varchar(100)',
#XML = #XML,
#KnownName = #KnownName
Result:
UNKNOWN_NAME1 UNKNOWN_NAME2
--------------- ---------------
Some value1 Some value2
The dynamically generated query looks like this:
select T.N.value('UNKNOWN_NAME1[1]', 'varchar(max)') as UNKNOWN_NAME1,
T.N.value('UNKNOWN_NAME2[1]', 'varchar(max)') as UNKNOWN_NAME2
from #XML.nodes('/*[local-name(.)=sql:variable("#KnownName")]') as T(N)
SE-Data

Related

What is the purpose of XMLNAMESPACES in a CTE query on the SSRS database? [duplicate]

I tryng to read xml file in sql server:
DECLARE #XMLToParse XML
-- Load the XML data in to a variable to work with.
-- This would typically be passed as a parameter to a stored proc
SET #XMLToParse = '<Response xmlns="http://tempuri.org/">
<AuthResult xmlns:a="http://schemas.datacontract.org/2004/07/Sistema.Soap.Contracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Result>
<a:Id_Value>500</a:Id_Value>
</a:Result>
<a:Result>
<a:Id_Value>895</a:Id_Value>
</a:Result>
</AuthResult>
</Response>'
-- Declare temp table to parse data into
DECLARE #ParsingTable TABLE
(Id_Value INT)
-- Parse the XML in to the temp table declared above
INSERT
INTO #ParsingTable
(Id_Value)
SELECT xmlData.A.value('.', 'INT') AS Id_Value
FROM #XMLToParse.nodes('Response/AuthResult/Result') xmlData(A)
-- Insert into the actual table from the temp table
SELECT Id_Value
FROM #ParsingTable
Apparently the code is correct but I can not get the values, where can I be wrong?
Use WITH XMLNAMESPACES to declare the namespaces and use the respective prefix for nodes not in the default namespace.
...
-- Parse the XML in to the temp table declared above
;WITH XMLNAMESPACES (DEFAULT 'http://tempuri.org/',
'http://schemas.datacontract.org/2004/07/Sistema.Soap.Contracts' as a,
'http://www.w3.org/2001/XMLSchema-instance' as i
)
INSERT
INTO #ParsingTable
(Id_Value)
SELECT xmlData.A.value('.', 'INT') AS Id_Value
FROM #XMLToParse.nodes('Response/AuthResult/a:Result') xmlData(A)
...

SQL Server 2016 extract info from XML

I've been through various posts on the same subject but I can't seem to be able to get to the data elements in my XML file.
Here is a snippet of my XML :
<ed:Certificate xmlns="http://sancrt.mpi.govt.nz/ecert/2013/ed-multiple-submission-schema.xsd" xmlns:ed="http://sancrt.mpi.govt.nz/ecert/2013/ed-submission-schema.xsd"> <ed:Status Code="39">Approved</ed:Status> <ed:LastUpdatedDate>2021-03-10T14:20:55+13:00</ed:LastUpdatedDate> <ed:Identifiers>
<ed:CertificateID>NZL2021/MEABC/26913T</ed:CertificateID>
<ed:TemplateID>ED1.6</ed:TemplateID> </ed:Identifiers> <ed:Exhausted>true</ed:Exhausted> <ed:AutoApproval>false</ed:AutoApproval> <ed:DepartureDate>2021-03-10</ed:DepartureDate> <ed:Parties>
<ed:ConsignorID>MEABC</ed:ConsignorID>
<ed:ConsigneeID>FLIGHT1</ed:ConsigneeID> </ed:Parties> <ed:Transport>
<ed:Ports>
<ed:LoadingPortID>NZTRG</ed:LoadingPortID>
</ed:Ports>
<ed:FinalDestination>OAKLAND, United States</ed:FinalDestination>
<ed:TransportMode>1</ed:TransportMode>
<ed:LocalCarrier>MDH2</ed:LocalCarrier>
<ed:CarrierName> Ever Given</ed:CarrierName>
<ed:ConveyanceReference>V1234</ed:ConveyanceReference> </ed:Transport> <ed:Remarks>
<ed:Remark>
<ed:RemarkType>Unofficial Information</ed:RemarkType>
<ed:RemarkValue>Vessel ETD - 19/03/21\nTARE WEIGHT - 2880 KGS</ed:RemarkValue>
</ed:Remark> </ed:Remarks> <ed:Products>
<ed:Product>
<ed:ProductItem>1</ed:ProductItem>
<ed:Exhausted>true</ed:Exhausted>
<ed:Origin>AO</ed:Origin>
<ed:Description>BONELESS BEEF RUMP CAP</ed:Description>
<ed:CommonName>Bovine</ed:CommonName>
<ed:EligibilityCountries>
<ed:EligibilityCountryID>US</ed:EligibilityCountryID>
</ed:EligibilityCountries>
<ed:IntendedUse>consumption</ed:IntendedUse>
<ed:GrossWeight unitCode="KGM">296.4</ed:GrossWeight>
<ed:NetWeight unitCode="KGM">271.6</ed:NetWeight>
<ed:Remarks>
<ed:Remark>
<ed:RemarkType>Product Statement</ed:RemarkType>
<ed:RemarkValue>Item No. 81625\nLabel Approval 2659305 & 91060858</ed:RemarkValue>
</ed:Remark>
</ed:Remarks>
<ed:Classifications>
<ed:Classification>
<ed:ClassificationType>Temperature</ed:ClassificationType>
<ed:ClassificationValue>chilled</ed:ClassificationValue>
</ed:Classification>
<ed:Classification>
<ed:ClassificationType>New Zealand Harmonised System Code</ed:ClassificationType>
<ed:ClassificationValue>020130</ed:ClassificationValue>
</ed:Classification>
<ed:Classification>
<ed:ClassificationType>Halal Product</ed:ClassificationType>
<ed:ClassificationValue>1</ed:ClassificationValue>
</ed:Classification>
</ed:Classifications>
<ed:Containers>
<ed:Container>
<ed:ID>CGMU3099999</ed:ID>
<ed:Seals>
<ed:ID>NZMPIXXXXX</ed:ID>
</ed:Seals>
</ed:Container>
</ed:Containers>
<ed:Packaging>
<ed:Package>
<ed:Quantity>29</ed:Quantity>
<ed:Type>CT</ed:Type>
<ed:Level>1</ed:Level>
<ed:ShippingMarks>
<ed:Name>MABC\n26913</ed:Name>
</ed:ShippingMarks>
</ed:Package>
</ed:Packaging>
<ed:Processes>
<ed:Process>
<ed:ProcessTypeCode>SLT</ed:ProcessTypeCode>
<ed:StartDate>2021-03-01</ed:StartDate>
<ed:EndDate>2021-03-01</ed:EndDate>
<ed:DateOverride>false</ed:DateOverride>
<ed:Premise>
<ed:ID>MEABC</ed:ID>
</ed:Premise>
</ed:Process>
<ed:Process>
<ed:ProcessTypeCode>PRO</ed:ProcessTypeCode>
<ed:StartDate>2021-03-02</ed:StartDate>
<ed:EndDate>2021-03-02</ed:EndDate>
<ed:DateOverride>false</ed:DateOverride>
<ed:Premise>
<ed:ID>MEABC</ed:ID>
</ed:Premise>
</ed:Process>
<ed:Process>
<ed:ProcessTypeCode>CST</ed:ProcessTypeCode>
<ed:StartDate>2021-03-02</ed:StartDate>
<ed:EndDate>2021-03-10</ed:EndDate>
<ed:DateOverride>false</ed:DateOverride>
<ed:Premise>
<ed:ID>MEABC</ed:ID>
</ed:Premise>
</ed:Process>
</ed:Processes>
</ed:Product>
</ed:Products>
</ed:Certificate>
This is what I have tried so far - Figured if I can access one element, I can slowly work on the rest
if OBJECT_ID('tempdb..#XmlImportTest') is not null
drop table #XmlImportTest
CREATE TABLE #XmlImportTest(
xmlFileName VARCHAR(300) NOT NULL,
xml_data XML NOT NULL
);
DECLARE #xmlFileName VARCHAR(200) ='K:\Upload\CSNXML\WaybillXml.xml'
EXEC('INSERT INTO #XmlImportTest(xmlFileName, xml_data)
SELECT ''' + #xmlFileName + ''', xmlData
FROM(
SELECT *
FROM OPENROWSET (BULK ''' + #xmlFileName + ''', SINGLE_BLOB) AS XMLDATA
) AS FileImport (XMLDATA)
')
DECLARE #XML AS XML, #hDoc AS INT, #SQL NVARCHAR (MAX)
SELECT #xml = (SELECT xml_data from #XmlImportTest)
EXEC sp_xml_preparedocument #hDoc OUTPUT, #XML
DECLARE #XML AS XML, #hDoc AS INT, #SQL NVARCHAR (MAX)
SELECT #xml = (SELECT xml_data from #XmlImportTest)
EXEC sp_xml_preparedocument #hDoc OUTPUT, #XML
;WITH XMLNAMESPACES ('http://sancrt.mpi.govt.nz/ecert/2013/ed-multiple-submission-schema.xsd' AS ed)
SELECT
p.value(N'#ProductItem',N'nvarchar(10)') AS ProductItem
FROM
#xml.nodes('/Certificate')
AS A(p)
CROSS APPLY a.p.nodes(N'Products/Product') AS B(m);
I don't get any results returned.
I get the same result using OPENROWSET as well.
Can someone please tell me how I can access this data element.
You seem to be getting confused about XML Namespaces. The example document defines two namespace URIs:
http://sancrt.mpi.govt.nz/ecert/2013/ed-multiple-submission-schema.xsd, which has no prefix so is considered to be the "default" namespace of the document.
http://sancrt.mpi.govt.nz/ecert/2013/ed-submission-schema.xsd, which uses the ed namespace prefix that, by eyeballing it, seems to be used on every element in the document so might as well be the default namespace.
Your simplest example is trying to extract the value of the /Certificate/Products/Product/ProductItem elements which could be done as simply as:
with xmlnamespaces (
default 'http://sancrt.mpi.govt.nz/ecert/2013/ed-submission-schema.xsd'
)
select productItem.value(N'text()[1]', N'int') as ProductItem
from #xml.nodes('/Certificate/Products/Product/ProductItem') as p(productItem);
Expanding on this to select a few more values, you can see the # being used here to access the unitCode attribute of an element:
with xmlnamespaces (
default 'http://sancrt.mpi.govt.nz/ecert/2013/ed-submission-schema.xsd'
)
select
product.value(N'(ProductItem/text())[1]', N'int') as ProductItem,
product.value(N'(Exhausted/text())[1]', N'bit') as Exhausted,
product.value(N'(Origin/text())[1]', N'nvarchar(2)') as Origin,
product.value(N'(GrossWeight/text())[1]', N'decimal(19,1)') as GrossWeight,
product.value(N'(GrossWeight/#unitCode)[1]', N'nvarchar(3)') as GrossWeightUnitCode
from #xml.nodes('/Certificate/Products/Product') as p(product);
It should be clear from the above two queries that the namespace prefixes used XPath query don't have to be the same as the ones used in the XML document - it's the namespace URIs themselves that matter. The prefixes in the document are used to link the elements (and sometimes attributes) to their namespace URIs, the prefixes used in XPath can be completely different so long as they reference the correct namespace URIs. e.g. this query returns the same result as the second example above, despite their being no submission prefixes in the source XML:
with xmlnamespaces (
'http://sancrt.mpi.govt.nz/ecert/2013/ed-multiple-submission-schema.xsd' as multiple,
'http://sancrt.mpi.govt.nz/ecert/2013/ed-submission-schema.xsd' as submission
)
select
product.value(N'(submission:ProductItem/text())[1]', N'int') as ProductItem,
product.value(N'(submission:Exhausted/text())[1]', N'bit') as Exhausted,
product.value(N'(submission:Origin/text())[1]', N'nvarchar(2)') as Origin,
product.value(N'(submission:GrossWeight/text())[1]', N'decimal(19,1)') as GrossWeight,
product.value(N'(submission:GrossWeight/#unitCode)[1]', N'nvarchar(3)') as GrossWeightUnitCode,
product.value(N'(submission:Remarks/submission:Remark/submission:RemarkType/text())[1]', N'nvarchar(50)') as item_remark
from #xml.nodes('/submission:Certificate/submission:Products/submission:Product') as p(product);

The xml root is repeating multiple time in sql?

I wanted the output of my xml to look like this:
<CustomConfigurationSteps>
<CustomConfigurations>
<CustomConfiguration SiteURL="abc">
<CustomElements>
<CustomElement Type="Searchtype" unit="3" price="5">
<ClassValue>AZSupreme</ClassValue>
</CustomElement>
</CustomElements>
<CustomElements>
<CustomElement Type="Searchtype" unit="3" price="5">
<ClassVaue>AZSupreme</ClassVaue>
</CustomElement>
</CustomElements>
</CustomConfiguration>
</CustomConfigurations>
</CustomConfigurationSteps>
I tried the below logic, but its not giving me the exact output.
DECLARE #xml xml
SET #xml = (SELECT
config.SiteURL AS '#SiteURL',
(SELECT
CustomConfiguration.Type AS '#Type',
CustomConfiguration.[PackageName] AS '#unit',
CustomConfiguration.[UseExecute] AS '#price',
ClassValue
FOR XML PATH('CustomElement'), TYPE) AS CustomElements
FROM
[dbo].[CustomConfigurationSteps] AS CustomConfiguration WITH (nolock)
INNER JOIN
WebSiteConfiguration AS config WITH (nolock) ON config.ConfigurationID = CustomConfiguration.[ConfigurationID]
WHERE
CustomConfiguration.[ConfigurationID] = 9
FOR XML path ('CustomConfiguration'), TYPE)
--set #xml1=( SELECT #xml FOR XML path ('CustomConfiguration') ,type)
SELECT #xml
FOR XML path ('CustomConfigurations'), ROOT ('CustomConfigurationSteps')
Try it like this (although this looks a little odd, especially the repeating <CustomElements> node.
A mockup table to simulate your issue:
DECLARE #tbl TABLE([Type] VARCHAR(100),unit int, price DECIMAL(10,4),ClassValue VARCHAR(100));
INSERT INTO #tbl VALUES('Searchtype 1',1,11,'AZSupreme 1')
,('Searchtype 2',2,22,'AZSupreme 2');
--The query
SELECT 'abc' AS [CustomConfiguration/#SiteURL]
,(
SELECT t.[Type] AS [CustomElement/#Type]
,t.unit AS [CustomElement/#unit]
,t.price AS [CustomElement/#pricee]
,t.ClassValue [CustomElement/ClassValue]
FROM #tbl t
FOR XML PATH('CustomElements'),TYPE
) AS CustomConfiguration
FOR XML PATH('CustomConfigurations'),ROOT('CustomConfigurationSteps');

Dynamic SQL - How to use a value from a result as a column name?

I am working on a dynamic SQL query for a MsSQL stored procedure.
There is a table search.ProfileFields that contains the actual column names in a table I need to query.
My goal is to have the SQL select the specific column in the table, dynamically from its parent query..
A little confusing, heres an example:
DECLARE #sql nvarchar(max)
SELECT #sql = '
SELECT
pfs.SectionID,
pfs.SectionName,
pfs.Link,
(
SELECT
pf.FieldID,
pf.FieldTitle,
pf.FieldSQL,
pf.Restricted,
pf.Optional,
(
SELECT
pf.FieldSQL
FROM
Resources.emp.EmployeeComplete as e
WHERE
e.QID = #QID
) as Value
FROM
search.ProfileFields as pf
WHERE
pf.SectionID = pfs.SectionID
ORDER BY
pf.[Order]
FOR XML PATH (''field''), ELEMENTS, TYPE, ROOT (''fields'')
)
FROM
search.ProfileFieldSections as pfs
WHERE
pfs.Status = 1
FOR XML PATH (''data''), ELEMENTS, TYPE, ROOT (''root'')'
PRINT #sql
EXECUTE sp_executesql #sql, N'#QID varchar(10)', #QID = #QID
In the inner most select. I am querying pf.FieldSQL. I am looking for the actual value that was received by the parent select.
search.ProfileFields has a column called FieldSQL with a few results such as Name, Age, Location.
That is what I am trying to get my inner most select to do.
SELECT Name FROM ... - Name in this case comes from the value of pf.FieldSQL.
How can I go about querying a dynamic column name in this situation?
Have a look at this answer for a couple of suggestions. If your table definition is complex or changes occasionally you probably should use pivot. Here's one that might work for you, so long as column names in the FieldSQL column are well defined, there are not too many of them, and they don't ever change or get added to:
DECLARE #sql nvarchar(max)
SELECT #sql = '
SELECT
pfs.SectionID,
pfs.SectionName,
pfs.Link,
(
SELECT
pf.FieldID,
pf.FieldTitle,
pf.FieldSQL,
pf.Restricted,
pf.Optional,
(
SELECT case pf.FieldSQL
when 'Name' then e.Name
when 'DOB' then convert(nvarchar(10), e.DOB, 126)
-- ... etc.
-- NOTE: may need to aggregated depending on uniqueness of QID:
-- when 'Name' then min(e.Name)
-- when 'DOB' then convert(nvarchar(10), min(e.DOB), 126)
end
FROM
Resources.emp.EmployeeComplete as e
WHERE
e.QID = #QID
) as Value
FROM
search.ProfileFields as pf
WHERE
pf.SectionID = pfs.SectionID
ORDER BY
pf.[Order]
FOR XML PATH (''field''), ELEMENTS, TYPE, ROOT (''fields'')
)
FROM
search.ProfileFieldSections as pfs
WHERE
pfs.Status = 1
FOR XML PATH (''data''), ELEMENTS, TYPE, ROOT (''root'')'
PRINT #sql
EXECUTE sp_executesql #sql, N'#QID varchar(10)', #QID = #QID
Take a look at "PIVOT" operators here PIVOT
Thisshould give you some ideas how to use them.

Concatenate XML without type casting to string

I have the following XML generated from various tables in my SQL SERVER database
<XMLData>
...
<Type>1</Type>
...
</XMLData>
AND
<XMLData>
...
<Type>2</Type>
...
</XMLData>
AND
<XMLData>
...
<Type>3</Type>
...
</XMLData>
The final output I need is single combined as follows:
<AllMyData>
<XMLData>
...
<Type>1</Type>
...
</XMLData>
<XMLData>
...
<Type>2</Type>
...
</XMLData>
<XMLData>
...
<Type>3</Type>
...
</XMLData>
<AllMyData>
NOTE - all the independent elements that I am combining have the same tag name.
Thanks in advance for looking this up.
I have the following XML generated from various tables in my SQL
SERVER database
Depends on how you have it but if it is in a XML variable you can do like this.
declare #XML1 xml
declare #XML2 xml
declare #XML3 xml
set #XML1 = '<XMLData><Type>1</Type></XMLData>'
set #XML2 = '<XMLData><Type>2</Type></XMLData>'
set #XML3 = '<XMLData><Type>3</Type></XMLData>'
select #XML1, #XML2, #XML3
for xml path('AllMyData')
I can't comment but can answer so even though I think a comment is more appropriate, I'll expand on what rainabba answered above to add a bit more control. My .Net code needs to know the column name returned so I can't rely on auto-generated names but needed the very tip rainabba provided above otherwise.
This way, the xml can effectively be concatenated into a single row and the resulting column named. You could use this same approach to assign the results to an XML variable and return that from a PROC also.
SELECT (
SELECT XmlData as [*]
FROM
(
SELECT
xmlResult AS [*]
FROM
#XmlRes
WHERE
xmlResult IS NOT NULL
FOR XML PATH(''), TYPE
) as DATA(XmlData)
FOR XML PATH('')
) as [someColumnName]
If you use for xml type, you can combine the XML columns without casting them. For example:
select *
from (
select (
select 1 as Type
for xml path(''), type
)
union all
select (
select 2 as Type
for xml path(''), type
)
union all
select (
select 3 as Type
for xml path(''), type
)
) as Data(XmlData)
for xml path(''), root('AllMyData'), type
This prints:
<AllMyData>
<XmlData>
<Type>1</Type>
</XmlData>
<XmlData>
<Type>2</Type>
</XmlData>
<XmlData>
<Type>3</Type>
</XmlData>
</AllMyData>
As an addendum to Mikael Eriksson's answer - If you have a process where you need to continually add nodes and then want to group that under a single node, this is one way to do it:
declare #XML1 XML
declare #XML2 XML
declare #XML3 XML
declare #XMLSummary XML
set #XML1 = '<XMLData><Type>1</Type></XMLData>'
set #XMLSummary = (SELECT #XMLSummary, #XML1 FOR XML PATH(''))
set #XML2 = '<XMLData><Type>2</Type></XMLData>'
set #XMLSummary = (SELECT #XMLSummary, #XML2 FOR XML PATH(''))
set #XML3 = '<XMLData><Type>3</Type></XMLData>'
set #XMLSummary = (SELECT #XMLSummary, #XML3 FOR XML PATH(''))
SELECT #XMLSummary FOR XML PATH('AllMyData')
I needed to do the same but without knowing how many rows/variables were concerned and without extra schema added so here was my solution. Following this pattern, I can generate as many snippets as I want, combine them, pass them between PROCS or even return them from procs and at any point, wrap them up in containers all without modifying the data or being forced to add XML structure into my data. I use this approach with HTTP end points to provide XML Web services and with another trick that converts XML into JSON, to provide JSON WebServices.
-- SETUP A type (or use this design for a Table Variable) to temporarily store snippets into. The pattern can be repeated to pass/store snippets to build
-- larger elements and those can be further combined following the pattern.
CREATE TYPE [dbo].[XMLRes] AS TABLE(
[xmlResult] [xml] NULL
)
GO
-- Call the following as much as you like to build up all the elements you want included in the larger element
INSERT INTO #XMLRes ( xmlResult )
SELECT
(
SELECT
'foo' '#bar'
FOR XML
PATH('SomeTopLevelElement')
)
-- This is the key to "concatenating" many snippets into a larger element. At the end of this, add " ,ROOT('DocumentRoot') " to wrapp them up in another element even
-- The outer select is a time from user2503764 that controls the output column name
SELECT (
SELECT XmlData as [*]
FROM
(
SELECT
xmlResult AS [*]
FROM
#XmlRes
WHERE
xmlResult IS NOT NULL
FOR XML PATH(''), TYPE
) as DATA(XmlData)
FOR XML PATH('')
) as [someColumnName]
ALTER PROCEDURE usp_fillHDDT #Code int
AS
DECLARE #HD XML,#DT XML;
SET NOCOUNT ON;
select invhdcode, invInvoiceNO,invDate,invCusCode,InvAmount into #HD
from dbo.trnInvoiceHD where invhdcode=#Code
select invdtSlNo No,invdtitemcode ItemCode,invdtitemcode ItemName,
invDtRate Rate,invDtQty Qty,invDtAmount Amount ,'Kg' Unit into #DT from
dbo.trnInvoiceDt where invDtTrncode=#Code
set #HD = (select * from #HD HD FOR XML AUTO,ELEMENTS XSINIL);
set #DT = (select* from #DT DT FOR XML AUTO,ELEMENTS XSINIL);
SELECT CAST ('<OUTPUT>'+ CAST (ISNULL(#HD,'') AS VARCHAR(MAX))+ CAST ( ISNULL(#DT,'') AS VARCHAR(MAX))+ '</OUTPUT>' AS XML)
public String ReplaceSpecialChar(String inStr)
{
inStr = inStr.Replace("&", "&");
inStr = inStr.Replace("<", "<");
inStr = inStr.Replace(">", ">");
inStr = inStr.Replace("'", "'");
inStr = inStr.Replace("\"", """);
return inStr;
}

Resources