I have looked throughout the interwebs (including SO but I have probably missed it) for a way to insert a node into existing XML which is contained in a variable without first creating as XML in a variable a string of the node which I would like to insert and using "set @XMLVariable01.modify('insert sql:variable("@XMLVariable02") as ...".
From the example below I would like to get as the final result:
<P xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<L01>
<A xsi:nil="true" />
<B xsi:nil="true" />
<C xsi:nil="true" />
</L01>
<L02>
<A>2</A>
<B xsi:nil="true" />
<C>x</C>
</L02>
</P>
Example:
declare
@P xml;
declare
@A varchar,
@B varchar,
@C varchar;
select
@P = (
select
@A as [A],
@B as [B],
@C as [C]
for xml path(N'L01'), root('P'), type, elements xsinil
);
select @P; --Initial result
select
@A = '2',
@B = NULL,
@C = 'x';
--select @P = ...?
select @P; --Final result
I did the following:
select
@P = (
select (
select
v.query('.')
from @P.nodes('P/L01') as t (v)),
(
select
@A as [A],
@B as [B],
@C as [C]
for xml path(N'L02'), type, elements xsinil
)
for xml path(N'P'), type, elements xsinil
);
Which comes close but I don't want the 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' anywhere other than in the initial/top line of the XML:
<P xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<L01>
<A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
<B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
<C xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
</L01>
<L02 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<A>2</A>
<B xsi:nil="true" />
<C>x</C>
</L02>
</P>
Edit (2018Dec14~1343): Based on Schnugo's helpful insight (Yes, I need/want the NULL values for the purpose of documentation that the indicated elements were accounted for but that no value was received. Also, I apologize but I am not able to fully grasp all that is being suggested in 1-5.), I have come up with the following:
select
@P = (
select
cast(replace(replace(cast(([XML].[Value]) as nvarchar(max)), cjR.Old01, cjR.New01), cjR.Old02, cjR.New02) as xml)
from (
select (
select
v.query('.')
from @P.nodes(N'P/L01') as t (v)),
(
select
@A as [A],
@B as [B],
@C as [C]
for xml path(N'L02'), type, elements xsinil
)
for xml path(N'P'), type, elements xsinil
) as [XML] ([Value])
cross join (
select
Value02 as Old01,
N'' as New01,
quotename(Value01, N'<>') as Old02,
quotename(Value01 + Value02, N'<>') as New02
from (
select
N'P',
N' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'
) as R (Value01, Value02)
) as cjR
);
It seems like such a hacky way to produce what should be such a simple operation but apparently it is not. I welcome any further advice to improve on this.