2010-08-24 32 views
3

是否可以使用XML DML語句來重命名非類型化XML列中的元素?SQL Server 2008:使用XML DML重命名元素?

我正在更新XML列上的XML模式集合,並且需要在重新命名一個元素之前修補現有的XML實例,然後才能應用最新的模式。

據我所知道的文檔,你只能插入/刪除節點或替換它們的值。

回答

2

俗話說,「哪裏有一個將有辦法」

這裏有兩種方法: 第一是簡單地從原來的以構建一個新的XML替換以前的XML新的元素名稱。在我的示例中,我已將腿/腿改爲肢體/肢體,但對於最簡單的模式而言,這可能會變得非常複雜,其次是組合插入和刪除的更合適的方法。

我它們合併成一個簡單的例子:

declare @xml as xml = '<animal species="Mouse"> 
    <legs> 
    <leg>Front Right</leg> 
    <leg>Front Left</leg> 
    <leg>Back Right</leg> 
    <leg>Back Left</leg> 
    </legs> 
</animal>' 

set @xml = (select 
    t.c.value('@species', 'varchar(max)') as '@species' 
    ,(select 
    ti.C.value('.', 'varchar(max)') 
from @Xml.nodes('//animal/legs/leg') ti(c) for xml path('limb'), /* root('limb'), */type) as limbs 
from @xml.nodes('//*:animal') t(c) for xml path('animal'), type) 

select @xml; 

while (@xml.exist('/animal/limbs/limb') = 1) begin 
    /*insert..*/ 
    set @xml.modify(' 
      insert <leg>{/animal/limbs/limb[1]/text()}</leg> 
      before (/animal/limbs/limb)[1] 
     '); 
    /*delete..*/ 
    set @xml.modify('delete (/animal/limbs/limb)[1]'); 
end 

set @xml.modify(' 
     insert <legs>{/animal/limbs/leg}</legs> 
     before (/animal/limbs)[1] 
    '); 
set @xml.modify('delete (/animal/limbs)[1]'); 

select @xml; 
+0

不完全是我正在尋找(希望),但仍然有幫助! – Sam 2010-12-21 22:54:14

+0

爲了清楚起見,示例是將第一種方法將腿/腿轉換爲四肢/四肢,然後將第四種方法從四肢/四肢轉換爲腿/腿。起初,我沒有注意到,當我嘗試複製/粘貼/調整時,感到困惑。第二種方法對我很有幫助。 – Ecyrb 2013-10-25 19:20:45

0

在SQL Server的單元測試的開發(ssut - 請參閱相關的博客文章),我想規範的XML集從一個測試對象來。因爲我會多次調用被測對象,每次設置和記錄名稱都是相同的。爲了便於閱讀,我希望將來自原始記錄的記錄集命名爲類似於<original_record_set><original_record /></original_record_set>,並且將記錄集設置爲 測試記錄將被命名爲類似於<test_record_set><test_record /></ test_record_set >

顯然,這是容易做到,如果你可以修改測試對象調用作爲第一:,

SET @output = (SELECT col1, col2 
    FROM @test_object_result 
    FOR xml path ( original_record'), root( original_record_set ')); 

但是因爲我調用同一個對象:

SET @output = (SELECT col1, col2 
    FROM @test_object_result 
    FOR xml path (test_record '), root(test_record_set ')); 

,然後多次,並且「for xml path」不允許path('...')root('...')方法中的變量,我不得不想出一種不同的方法。

該函數接受一個xml樹並構建一棵新樹,用@relation_name的值替換根節點,並用@tuple_name替換每個記錄的名稱。即使每個記錄有不同的數字,新樹也會以原始的所有屬性構建。

EXCEPTIONS
顯然這不適用於多個元素級別!我已經專門構建它來處理基於單級屬性的樹,如下面的示例所示。我將來可能會爲它構建一個多層次的混合屬性/元素樹,但是我認爲現在我已經解決了下面的基本問題,這樣做的方法就變得很明顯了,並且會將這個練習留給讀者等待那段時間。

USE [unit_test]; 
GO 
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[standardize_record_set]') AND type IN (N'FN', N'IF', N'TF', N'FS', N'FT')) 
    DROP FUNCTION [dbo].[standardize_record_set]; 
GO 
SET ANSI_NULLS ON; 
GO 
SET QUOTED_IDENTIFIER ON; 
GO 
SET nocount ON; 
GO 
/* 
DECLARE 
    @relation_name nvarchar(150)= N'standardized_record_set', 
    @tuple_name nvarchar(150)= N'standardized_record', 
    @xml   xml, 
    @standardized_result xml; 

SET @xml='<Root> 
    <row id="12" two="now1" three="thr1" four="four1" /> 
    <row id="232" two="now22" three="thr22" /> 
    <row id="233" two="now23" three="thr23" threeextra="extraattrinthree" /> 
    <row id="234" two="now24" three="thr24" fourextra="mealsoin four rwo big mone" /> 
    <row id="235" two="now25" three="thr25" /> 
</Root>'; 

execute @standardized_result = [dbo].[standardize_record_set] @[email protected]_name, @[email protected]_name, @[email protected]; 
select @standardized_result; 

*/ 
CREATE FUNCTION [dbo].[standardize_record_set] (@relation_name nvarchar(150)= N'record_set', 
               @tuple_name nvarchar(150)= N'record', @xml xml) 
returns XML 
AS 
    BEGIN 
     DECLARE 
     @attribute_index int = 1, 
     @attribute_count int = 0, 
     @record_set  xml = N'<' + @relation_name + ' />', 
     @record_name  nvarchar(50) = @tuple_name, 
     @builder   nvarchar(max), 
     @record   xml, 
     @next_record  xml; 
     DECLARE @record_table TABLE (
     record xml); 

     INSERT INTO @record_table 
     SELECT t.c.query('.') AS record 
     FROM @xml.nodes('/*/*') T(c); 

     DECLARE record_table_cursor CURSOR FOR 
     SELECT cast([record] AS xml) 
     FROM @record_table 

     OPEN record_table_cursor 

     FETCH NEXT FROM record_table_cursor INTO @next_record 

     WHILE @@FETCH_STATUS = 0 
     BEGIN 
      SET @attribute_index=1; 
      SET @attribute_count = @next_record.query('count(/*[1]/@*)').value('.', 'int'); 
      SET @builder = N'<' + @record_name + N' '; 

      -- build up attribute string 
      WHILE @attribute_index <= @attribute_count 
       BEGIN 
        SET @builder = @builder + @next_record.value('local-name((/*/@*[sql:variable("@attribute_index")])[1])', 
                   'varchar(max)') + '="' + @next_record.value('((/*/@*[sql:variable("@attribute_index")])[1])', 
                              'varchar(max)') + '" '; 
        SET @attribute_index = @attribute_index + 1 
       END 

      -- build record and add to record_set 
      SET @record = @builder + ' />'; 
      SET @record_set.modify('insert sql:variable("@record") into (/*)[1]'); 

      FETCH NEXT FROM record_table_cursor INTO @next_record 
     END 

     CLOSE record_table_cursor; 

     DEALLOCATE record_table_cursor; 

     RETURN @record_set; 
    END; 

GO 
0

是的,你可以使用DML通過在你想要重命名的節點剪斷它,在注射該元素一個新的節點,然後粘貼剪斷元素回該節點的XML重命名的元素。我已經做了一個SQL小提琴演示。http://sqlfiddle.com/#!3/dc64d/1 這將改變

<animal species="Mouse"> 
<legs> 
<leg>Front Right</leg> 
<leg>Front Left</leg> 
<leg>Back Right</leg> 
<leg>Back Left</leg> 
</legs> 
</animal> 

<animal species="Mouse"> 
<armsandlegs> 
<leg>Front Right</leg> 
<leg>Front Left</leg> 
<leg>Back Right</leg> 
<leg>Back Left</leg> 
</armsandlegs> 
</animal> 

SqlFiddle看起來早已打破了我的解決方案。從記憶中粘貼我的解決方案的基礎下面...

DECLARE @XML2 xml 
DECLARE @XML3 xml = '<limbs></limbs>' 
DECLARE @XML xml = 
'<animal species="Mouse"> 
<legs> 
<leg>Front Right</leg> 
<leg>Front Left</leg> 
<leg>Back Right</leg> 
<leg>Back Left</leg> 
</legs> 
</animal>' 

SET @XML2 = @XML.query('animal/legs/*') 

SET @XML.modify(' 
insert  
    (sql:variable("@XML3")) 
after 
    (/animal/legs)[1] 
') 
SET @XML.modify(' 
delete (/animal/legs[1]) 
') 
SET @XML.modify(' 
insert  
    (sql:variable("@XML2")) 
as last into 
    (/animal/limbs)[1] 
') 
select @XML 
+0

在你的答案中包含小提琴,因此它獨立。 – J0e3gan 2016-01-28 17:08:47