我正在编写一个存储过程来处理用户上传的XML数据:
<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>
我想使用模式来确保实体有效,但我不希望整个过程因一个无效实体而失败。相反,我想将所有无效实体记录到表中并正常处理有效实体。
有推荐的方法吗?
答案 0 :(得分:1)
纯SQL方法是:
创建定义<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>
'
(一次性操作)
使用XML查询从<Person>
中选择每个<People>
节点作为单独的行。
在该查询上声明游标,并将每行选择为无类型的xml变量。在select之后,尝试从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="..."/>
:好的<Person Id="2" FirstName="..." LastName="..."/>
:好的<Person Id="f" FirstName="..." LastName="..."/>
:失败了<Person Id="4" FirstName="..." LastName="..."/>
:好的<Person Id="5" FirstName="..." LastName="..."/>
:好的
更简单的选择是创建一个CLR存储过程,该过程将用.NET语言解析XML。