代码之家  ›  专栏  ›  技术社区  ›  Sam

SQL Server 2008:使用XML DML重命名元素?

  •  3
  • Sam  · 技术社区  · 14 年前

    我正在更新XML列上的XML架构集合,需要通过重命名一个元素来修补现有的XML实例,然后才能应用最新的架构。

    3 回复  |  直到 14 年前
        1
  •  2
  •   Dog Ears    14 年前

    俗话说,

    第一种方法是简单地用一个新的xml替换以前的xml,这个xml是用新元素名从原来的xml构造的。在我的例子中,我把Legs/Leg改成了frambers/Limb,除了最简单的模式,这可能会变得非常复杂

    第二,插入和删除相结合的更合适的方法。

    我把它们组合成一个简单的例子:

    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;
    
        2
  •  0
  •   Harald Brinkhof    12 年前

    在开发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 ( test_record  '), root( test_record_set '));
    

    然后:

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

    但是,由于我多次调用同一对象,并且“for xml path”不允许 path('...') root('...')

    此函数接受一个xml树并构建一个新树,用值替换根节点 @relation_name @tuple_name . 新树是用原始树的所有属性构建的,即使每个记录有不同的数字。

    例外情况
    显然,这不适用于多个元素级别!我专门构建了它来处理一个基于单层属性的树,如下面的示例所示。我可能会在将来为多层混合属性/元素树构建它,但是我认为这样做的方法变得很明显,因为我已经解决了下面的基本问题,并且将把这个练习留给读者等待。

    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] @relation_name=@relation_name, @tuple_name=@tuple_name, @xml=@xml;
    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 
    
        3
  •  0
  •   Jailhouse Joe    7 年前

    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
    
    推荐文章