Reputation: 531
I have the following XML structure:
set @MailXML =
'<MailingCompany>
<Mailman>
<Name>Jamie</Name>
<Age> 24 </Age>
<Letter>
<DestinationAddress> 440 Mountain View Parade </DestinationAddress>
<DestinationCountry> USA </DestinationCountry>
<OriginCountry> Australia </OriginCountry>
<OriginAddress> 120 St Kilda Road </OriginAddress>
</Letter>
</Mailman>
</MailingCompany>'
My SQL currently looks like this:
-- Mail Insertion
INSERT INTO mailDB.dbo.Mailman
SELECT
m.value('Name[1]','varchar(50)') as Name,
m.value('Age[1]','varchar(50)') as Age
FROM
@MailXML.nodes('/MailingCompany/Mailman') as A(m)
SET @MailPersonFK = SCOPE_IDENTITY();
-- Letter Insertion
INSERT INTO mailDB.dbo.Letter
SELECT
l.value('DestinationAddress[1]', 'varchar(50)') as DestinationAddress,
l.value('DestinationCountry[1]', 'varchar(50)') as DestinationCountry,
l.value('OriginCountry[1]', 'varchar(50)') as OriginCountry,
l.value('OriginAddress[1]', 'varchar(50)') as OriginAddress
@MailPersonFK as MailID
FROM
@MailXML.nodes('MailingCompany/Mailman/Letter') as B(l)
I am trying to extract the Mailman
and Letter data into their own respective tables. I have got that working however my issue is that the MailCompany
node is dynamic. Sometimes it may be MailVehicle
, for example, and I still need
to read the corresponding Mailman
and Letter
node data and insert them into their own respective tables.
So both
FROM @MailXML.nodes('/MailingCompany/Mailman') as A(t)
and
FROM @MailXML.nodes('MailingCompany/Mailman/Letter') as B(l)
Will need to be changed to allow MailingCompany
to be dynamic.
I have tried to extract the parent node and concatenate it into a string to put into the .nodes function like the following:
set @DynXML = '/' + @parentNodeVar + '/Mailman'
FROM @MailXML.nodes(@DynXML) as A(t)
However I get the following error:
The argument 1 of the XML data type method "nodes" must be a string literal.
How can I overcome this dynamic XML issue?
Thank you very much in advance
Upvotes: 0
Views: 2365
Reputation: 67291
Look at this reduced example:
DECLARE @xml1 XML=
N'<MailingCompany>
<Mailman>
<Name>Jamie</Name>
<Letter>
<DestinationAddress> 440 Mountain View Parade </DestinationAddress>
</Letter>
</Mailman>
</MailingCompany>';
DECLARE @xml2 XML=
N'<OtherName>
<Mailman>
<Name>Jodie</Name>
<Letter>
<DestinationAddress> This is the other address </DestinationAddress>
</Letter>
</Mailman>
</OtherName>';
SELECT @xml1.value(N'(*/Mailman/Name)[1]','nvarchar(max)') AS Mailman_Name
,@xml1.value(N'(*/Mailman/Letter/DestinationAddress)[1]','nvarchar(max)') AS DestinationAddress
SELECT @xml2.value(N'(*/Mailman/Name)[1]','nvarchar(max)') AS Mailman_Name
,@xml2.value(N'(*/Mailman/Letter/DestinationAddress)[1]','nvarchar(max)') AS DestinationAddress
You can replace a node's name with *
.
Another trick is the deep search with //
(same result as before):
SELECT @xml1.value(N'(//Name)[1]','nvarchar(max)') AS Mailman_Name
,@xml1.value(N'(//DestinationAddress)[1]','nvarchar(max)') AS DestinationAddress
SELECT @xml2.value(N'(//Name)[1]','nvarchar(max)') AS Mailman_Name
,@xml2.value(N'(//DestinationAddress)[1]','nvarchar(max)') AS DestinationAddress
The general rule: Be as specific as possible.
Upvotes: 3