如何使用MS SQL中的命名空间针对XSD验证XML存储过程参数?

时间:2014-02-12 21:51:31

标签: sql xml stored-procedures xsd

我有一个People的数据集,我希望能够将该集合插入到我的表中,但验证输入XML是否与我创建的XML SCHEMA COLLECTION匹配。在我不使用命名空间的更简单的代码版本中,我能够实现这一点,但我希望能够使用用户定义的数据类型以及命名空间来实现。当我尝试使用下面的代码时,我得到消息2260,级别16,状态1,过程sp_InsertPerson,第16行 XQuery [nodes()]:没有名为' People'

的元素

我已经尝试了很多东西,而且还没有能够弄清楚如何实现这一目标。以下是创建存储过程的代码:

USE [A_IndexingTest]
GO
CREATE PROCEDURE [dbo].[sp_InsertPerson]
(
    @xmlData XML (dbo.PersonSchemaCollection)
)
AS
BEGIN

INSERT INTO dbo.Person
  (LastName, FirstName, Gender, DateOfBirth, IsFriendly)
SELECT 
  person.field.value('(FirstName)[1]', 'nvarchar(100)'),
  person.field.value('(LastName)[1]', 'nvarchar(100)'),
  person.field.value('(Gender)[1]', 'char(1)'),
  person.field.value('(DateOfBirth)[1]', 'datetime'),
  person.field.value('(IsFriendly)[1]', 'bit')
FROM @xmlData.nodes('/People/Person') AS person(field)

SELECT CAST(SCOPE_IDENTITY() as int)
END
GO

创建XSD:

USE [A_IndexingTest]
GO
CREATE XML SCHEMA COLLECTION [dbo].[PersonSchemaCollection] AS
N'
    <?xml version="1.0"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
     xmlns:xs="http://www.w3.org/2001/XMLSchema"
     targetNamespace="http://example.org/People"
     xmlns:tns="http://example.org/People">

    <xs:simpleType name="firstName">
      <xs:restriction base="xs:string">
        <xs:minLength value="1" />
        <xs:maxLength value="100" />
      </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="lastName">
      <xs:restriction base="xs:string">
        <xs:minLength value="1" />
        <xs:maxLength value="100" />
      </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="gender">
      <xs:restriction base="xs:string">
        <xs:minLength value="1" />
        <xs:maxLength value="1" />
      </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="dateOfBirth">
      <xs:restriction base="xs:date">
      </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="isFriendly">
      <xs:restriction base="xs:boolean">          
      </xs:restriction>
    </xs:simpleType>

    <xs:element name="People">
      <xs:complexType>
        <xs:sequence>
          <xs:element maxOccurs="unbounded" name="Person">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="FirstName" type="tns:firstName" minOccurs="1" maxOccurs="1" />
                <xs:element name="LastName" type="tns:lastName" minOccurs="1" maxOccurs="1" />
                <xs:element name="Gender" type="tns:gender" minOccurs="1" maxOccurs="1" />
                <xs:element name="DateOfBirth" type="tns:dateOfBirth" minOccurs="1" maxOccurs="1" />
                <xs:element name="IsFriendly" type="tns:isFriendly" minOccurs="1" maxOccurs="1" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:sequence>
      </xs:complexType>
    </xs:element>
</xs:schema>'

1 个答案:

答案 0 :(得分:0)

因为我正在使用targetNamespace,所以我需要在创建存储过程时引用命名空间。

CREATE PROCEDURE [dbo].[sp_InsertPerson] (
    @xmlData XML (dbo.PersonSchemaCollection)
)
AS
BEGIN

-- this is the part that I was missing
WITH XMLNAMESPACES('http://example.org/People' as tns)

INSERT INTO dbo.Person
  (LastName, FirstName, Gender, DateOfBirth, IsFriendly)
SELECT 

  -- additionally note the tns prefix for all of the fields and nodes
  person.field.value('(tns:FirstName)[1]', 'nvarchar(100)'),
  person.field.value('(tns:LastName)[1]', 'nvarchar(100)'),
  person.field.value('(tns:Gender)[1]', 'char(1)'),
  person.field.value('(tns:DateOfBirth)[1]', 'datetime'),
  person.field.value('(tns:IsFriendly)[1]', 'bit')
FROM @xmlData.nodes('/tns:People/tns:Person') AS person(field)

SELECT CAST(SCOPE_IDENTITY() as int)
END
GO