T-SQL DML:如何更改/添加现有XML节点的父节点?

时间:2012-09-17 21:26:07

标签: sql-server xml tsql xquery

我的数据库中有几个需要更新的XML。以下是它们的简单表示:

<root>
  <child1>blah</child1>
</root>

我需要用另一个元素包装<child1>来获得这样的结构:

<root>
  <child1Root>
    <child1>blah</child1>
  </child1Root>
</root>

看似简单,但我不是T-SQL和DML专家。

注意:如果有兴趣知道更新的原因,答案是下面的XML不能使用DataContractSerializer反序列化。它可以使用XmlSerializer和XmlArray属性反序列化,但不能反序列化DCS:

<root>
  <child1>blah</child1>
  <child2>blah</child2>
</root>

3 个答案:

答案 0 :(得分:2)

如果您的实际代码与示例一样简单,那么您可以这样做:

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

如果您的真实XML稍微复杂一些,那么您可能需要将其分解。

答案 1 :(得分:0)

蛮力方法:

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       

答案 2 :(得分:0)

这是一份工作样本。鉴于有效的XML具有严格的规则,我认为没有理由为什么字符串操作不起作用。至少,“&lt;”这是字符串搜索的关键,不应该存在于XML标记名之外。

-- 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