Reputation: 8926
I have several XML in my DB that need to be updated. Here is the simplistic representation of them:
<root>
<child1>blah</child1>
</root>
I need to wrap <child1>
with another element to get structure like this:
<root>
<child1Root>
<child1>blah</child1>
</child1Root>
</root>
Appears easy but I am not T-SQL and DML specialist.
Note: if one is interested in knowing why to update, the answer is that the XML below is not deserializable using DataContractSerializer. It can be deserialized using XmlSerializer and XmlArray attribute but not DCS:
<root>
<child1>blah</child1>
<child2>blah</child2>
</root>
Upvotes: 0
Views: 1456
Reputation: 14379
If your actual code is as simple as your example then you could just do this:
DECLARE @yourTable TABLE ( yourXML XML )
INSERT INTO @yourTable ( yourXML )
VALUES
( '<root><child1>blah1</child1></root>' ),
( '<root><child1>blah2</child1></root>' )
UPDATE @yourTable
SET yourXML = yourXML.query('root/child1').query('<root><child1Root>{.}</child1Root></root>')
SELECT * FROM @yourTable
If your real XML is a bit more complicated then you might need to break it up.
Upvotes: 2
Reputation: 107716
Here's a working sample. I can think of no reason why the string manipulations would not work, given that valid XML has strict rules. At the very least, "<" which is key to the string searches should never exist outside of XML tag names.
-- create a sample table variable with a few variations
declare @T table (sample xml)
insert @T select '
<root>
<child1>blah</child1>
</root>'
insert @T select '
<root>
<child1>blah1</child1>
<child1>blah2</child1>
</root>'
insert @T select '
<root>
<child1>
blah1
<child2>blah2</child2>
</child1>
</root>'
insert @T select '
<root>
<child0>
<child1>
<child4>
<child3>blah2</child3>
</child4>
</child1>
</child0>
</root>'
-- peek at the content
select * from @T
-- perform the replacements as many times as required
-- note that the string "stackoverflow123" is expected to NEVER
-- exist in your data, or use another string if it does!
while @@rowcount > 0
begin
update T
set sample = stuff(X.A, Y.B, Z.C - Y.B + 9, '<child1Root>'+
replace(replace(
SUBSTRING(X.A, Y.B, Z.C - Y.B + 9),
'<child1>','<stackoverflow123>'),
'</child1>','</stackoverflow123>')
+'</child1Root>')
from @T T
cross apply (
select convert(varchar(max),sample)) X(A)
cross apply (
select patindex('%<child1>%</child1>%', X.A)) Y(B)
cross apply (
select charindex('</child1>', X.A, Y.B+1)) Z(C)
where Z.C > 0
end
-- finally revert the placeholder string back to "child1"
update @T
set sample = replace(convert(varchar(max),sample), 'stackoverflow123', 'child1')
-- inspect the finished product
select * from @T
Upvotes: 0
Reputation: 8926
Brute force approach:
DECLARE @myDoc xml
SET @myDoc = '
<root>
<child1>blah</child1>
</root>'
SELECT @myDoc
DECLARE @child1 xml;
SET @child1 = @myDoc.query('/root/child1')
SELECT @child1
SET @myDoc.modify('
insert <child1Root />
into (/root)[1]')
SELECT @myDoc
SET @myDoc.modify('
insert sql:variable("@child1")
into (/root/child1Root)[1]')
SELECT @myDoc
SET @myDoc.modify('
delete /root/child1')
SELECT @myDoc
Upvotes: 0