代码之家  ›  专栏  ›  技术社区  ›  Katherine Elizabeth Lightsey

sql xquery;更新类型化xml中的属性

  •  0
  • Katherine Elizabeth Lightsey  · 技术社区  · 6 年前

    我正在尝试更新类型化xml中的属性。在过去,我是通过在非类型化对象中构建XML,然后将其设置为类型化对象(这样就避免了这个问题)来实现的,但是我想知道如何直接修改类型化数据。

    我的架构是:

    if exists (select [xml_collection_id]
               from   sys.[xml_schema_collections] as [xsc]
               where  [xsc].name = 'xsc_test_stack'
                      and [xsc].[schema_id] = schema_id(N'chamomile'))
      drop xml schema collection [chamomile].[xsc_test_stack];
    
    go
    
    create xml schema collection [chamomile].[xsc_test_stack] as N'<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:chamomile="https://github.com/KELightsey/chamomile" targetNamespace="https://github.com/KELightsey/chamomile">
      <xsd:element name="test_stack">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="description" type="xsd:string" minOccurs="1" maxOccurs="1" />
            <xsd:element name="test_stack_detail" type="chamomile:any_complex_type" minOccurs="0" maxOccurs="unbounded" />
            <xsd:element name="test" type="chamomile:any_complex_type" minOccurs="0" maxOccurs="unbounded" />
          </xsd:sequence>
          <xsd:attribute name="name" type="xsd:string" use="required" />
          <xsd:attribute name="test_count" type="xsd:int" use="required" />
          <xsd:attribute name="pass_count" type="xsd:int" use="required" />
          <xsd:attribute name="timestamp" type="xsd:dateTime" use="required" />
         <xsd:anyAttribute processContents="lax" />
        </xsd:complexType>
      </xsd:element>
    
        <xsd:complexType name="any_complex_type">
            <xsd:complexContent>
                <xsd:restriction base="xsd:anyType">
                    <xsd:sequence>
                        <xsd:any minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
                    </xsd:sequence>
                    <xsd:anyAttribute processContents="lax" />
                </xsd:restriction>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:schema>';
    
    go 
    

    我建造的结构类型示例如下:

    declare @test [xml]([chamomile].[xsc_test_stack]) = N'
         <chamomile:test_stack xmlns:chamomile="https://github.com/KELightsey/chamomile" name="[chamomile].[person_test].[get_age]" test_count="2" pass_count="2" timestamp="2018-06-24T15:50:19.3466667">
           <description>This test stack consists of tests which validate the functionality of the age calculation for a person.</description>
         </chamomile:test_stack>';
    go
    
    declare @test [xml]([chamomile].[xsc_test_stack]) = N'
         <chamomile:test_stack xmlns:chamomile="https://github.com/KELightsey/chamomile" name="[chamomile].[person_test].[get_age]" test_count="2" pass_count="2" timestamp="2018-06-24T15:50:19.3466667">
           <description>This test stack consists of tests which validate the functionality of the age calculation for a person.</description>
           <test_stack_detail>
              <any_valid_xml_goes_here />
           </test_stack_detail>
         </chamomile:test_stack>';
    go
    

    我试过的是:

    set @test_stack.modify(N'replace value of (//@test_count)[1] with sql:variable("@count")');
    

    这又回来了 :msg 9306,16级,状态1,第28行 xquery[modify()]:replace value of'的目标不能是union类型,found'(attribute(test_count,xs:int)attribute(test_count,xs:anysimpleType))?'.

    set @test_stack.modify(N'declare namespace chamomile="https://github.com/KELightsey/chamomile"; 
        replace value of (chamomile:test_stack/@test_count)[1] with sql:variable("@count")');
    

    这又回来了 :msg 9306,16级,状态1,第25行 xquery[modify()]:replace value of'的目标不能是union类型,found'(attribute(test_count,xs:int)attribute(test_count,xs:anysimpleType))?'.

    我花了几个小时在谷歌上搜索这个。有很多例子使用非类型化的xml,还有一些使用类型化的xml,仍然抛出相同的异常。

    我很感激你的洞察力。

    谢谢, 凯瑟琳

    1 回复  |  直到 6 年前
        1
  •  1
  •   Gottfried Lesigang    6 年前

    我必须承认,我也没有找到任何直截了当的方法。好像是个虫子,至少我看不出有什么意义。解决方案是一个简单的转换,但这与您在初始行中描述的解决方案非常接近:

    declare @test [xml]([chamomile].[xsc_test_stack]) = 
    N'<chamomile:test_stack xmlns:chamomile="https://github.com/KELightsey/chamomile" name="[chamomile].[person_test].[get_age]" test_count="2" pass_count="2" timestamp="2018-06-24T15:50:19.3466667">
           <description>This test stack consists of tests which validate the functionality of the age calculation for a person.</description>
         </chamomile:test_stack>';
    
    DECLARE @cnt INT=99;
    
    DECLARE @intermediate XML=CAST(@test AS XML); --magic happens here
    SET @intermediate.modify('declare namespace chamomile="https://github.com/KELightsey/chamomile"; 
                              replace value of (chamomile:test_stack/@test_count)[1] with sql:variable("@cnt")');
    
    SET @test=@intermediate; --re-assign to typed XML
    
    SELECT @test;