2011-11-29 77 views
0

我正在写一个存储过程来处理由用户上传的XML数据:验证各个XML元素2008R2

<People> 
    <Person Id="1" FirstName="..." LastName="..." /> 
    <Person Id="2" FirstName="..." LastName="..." /> 
    <Person Id="3" FirstName="..." LastName="..." /> 
    <Person Id="4" FirstName="..." LastName="..." /> 
    <Person Id="5" FirstName="..." LastName="..." /> 
</People> 

我想用一个模式来确保实体是有效的,但我不希望整个过程因为一个无效的实体而失败。相反,我想将所有无效实体记录到一个表中,并按正常方式处理有效实体。

有没有推荐的方法来做到这一点?

回答

1

纯SQL的方法是:

  1. 创建一个架构集合定义<Person>

    CREATE XML SCHEMA COLLECTION [dbo].[testtest] AS 
    N'<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
        <xs:element name="Person"> 
         <xs:complexType> 
         <xs:attribute name="Id" type="xs:int" use="required"/> 
         <xs:attribute name="FirstName" type="xs:string" use="required"/> 
         <xs:attribute name="LastName" type="xs:string" use="required"/> 
         </xs:complexType> 
        </xs:element> 
        </xs:schema> 
    ' 
    

    (一次性操作)

  2. 有一个XML查询选择作为单独的行,来自<People>的每个<Person>节点。

  3. 在该查询上声明一个游标,并将每行都选择到一个无类型的xml变量中。选择之后,尝试从try-catch块内分配一个类型化的xml变量。

生成的代码看起来像:

declare @source xml = N' 
    <People> 
     <Person Id="1" FirstName="..." LastName="..." /> 
     <Person Id="2" FirstName="..." LastName="..." /> 
     <Person Id="f" FirstName="..." LastName="..." /> 
     <Person Id="4" FirstName="..." LastName="..." /> 
     <Person Id="5" FirstName="..." LastName="..." /> 
    </People>'; 

declare foo cursor 
local 
forward_only 
read_only 
for 
    select t.p.query('.') 
    from @source.nodes('People/Person') as t(p) 
; 

declare @x xml (dbo.testtest); 
declare @x_raw xml; 

open foo; 

fetch next from foo into @x_raw; 

while @@fetch_status = 0 
begin 
    begin try 
    set @x = @x_raw; 
    print cast(@x_raw as nvarchar(max)) + ': OK'; 
    end try 
    begin catch 
    print cast(@x_raw as nvarchar(max)) + ': FAILED'; 
    end catch; 

    fetch next from foo into @x_raw; 
end; 

close foo; 
deallocate foo; 

结果:

<Person Id="1" FirstName="..." LastName="..."/>:OK
<Person Id="2" FirstName="..." LastName="..."/>:OK
<Person Id="f" FirstName="..." LastName="..."/>:失败
<Person Id="4" FirstName="..." LastName="..."/>:OK
<Person Id="5" FirstName="..." LastName="..."/>:OK


一个更简单的方法是创建一个CLR存储过程将在.NET语言解析XML。

+0

你能给我一个XML查询的例子来选择每个元素作为一个单独的行吗?另外,如果我使用CLR存储过程,会不会影响存储过程的性能? –

+0

@JustinRusbatch查看修改。至于性能,我认为CLR实际上会更快,但试试看。 – GSerg