为什么我的XML无法在SQL Server 2008中的类型化XML列中进行验证?

| 超短版: 当我快写完问题时,我解决了这个问题。答案很快就会到来。 精简版: 为什么SQL Server拒绝将我的XML插入类型化XML列中? XML是使用.NET 4中的“ 0”生成的。 更长的版本: 我有一个可以使用
XmlSerializer
成功进行序列化的类。更具体地说,我可以使用
XmlSerializer
成功序列化该类的数组。 我在SQL Server 2008表中有一个XML列。如果我只是使用无类型的XML列,则插入
XmlSerializer.Serialize
的输出效果很好(我使用的是Entity Framework,它将XML列转换为
string
类型)。但是,我想使该列成为类型化XML列。这样做时,无论尝试什么,我似乎都无法从序列化程序中获取XML以成功进行验证。 这是我用来在SQL Server中创建类型化XML列的(轻度混淆)XSD:
<?xml version=\"1.0\" encoding=\"utf-8\"?>
<xs:schema id=\"ArrayOfMyObject\"
    targetNamespace=\"http://www.myproduct.com/2011/04/08/ArrayOfMyObject.xsd\"
    xmlns=\"http://www.myproduct.com/2011/04/08/ArrayOfMyObject.xsd\"
    xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"
>
    <xs:complexType name=\"MyObject\">
        <xs:all minOccurs=\"0\" maxOccurs=\"1\">
            <xs:element name=\"CD\" type=\"xs:int\" />
            <xs:element name=\"CI\" type=\"xs:string\" />
            <xs:element name=\"CT\" type=\"xs:int\" />
            <xs:element name=\"CY\" type=\"xs:int\" />
            <xs:element name=\"LD\" type=\"xs:int\" />
            <xs:element name=\"SomeName\" type=\"xs:string\" />
            <xs:element name=\"SomeNumber\" type=\"xs:string\" />
            <xs:element name=\"SD\" type=\"xs:int\" />
            <xs:element name=\"ZP\" type=\"xs:string\" />
            <xs:element name=\"State\">
                <xs:simpleType>
                    <xs:restriction base=\"xs:string\">
                        <xs:pattern value=\"[A-Z][A-Z]\" />
                    </xs:restriction>
                </xs:simpleType>
            </xs:element>
        </xs:all>
    </xs:complexType>

    <xs:element name=\"ArrayOfMyObject\">
        <xs:complexType>
            <xs:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">
                <xs:element name=\"MyObject\" type=\"MyObject\" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>
我在SQL Server中使用以下方法创建了架构集合:
CREATE XML SCHEMA COLLECTION [dbo].[MySchemaCollection] AS
\'<The XSD from above>\'
(在这里进行明显的替换)。请注意,我没有这样做:
CREATE XML SCHEMA COLLECTION [dbo].[MySchemaCollection] AS
N\'<The XSD from above which now gives an error>\'
因为
NVARCHAR
类型与utf-8的组合会导致SQL Server产生如下错误:   消息9402,第16级,状态1,第3行   XML解析:第1行,字符39,无法切换编码 现在,我重新创建表,相关列为:
[MyXmlColumn] [xml](DOCUMENT [dbo].[MySchemaCollection]) NULL
我希望插入的内容是
DOCUMENT
,但我也尝试将列创建为
CONTENT
,但无济于事。 我创建
XmlSerializer
_xml = new XmlSerializer(typeof(MyObject[]));
并调用串行器
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(\"t\", \"http://www.myproduct.com/2011/04/08/ArrayOfMyObject.xsd\");
_xml.Serialize(serializationStream, graph, ns);
其中,
serializationStream
当然是输出流(在这种情况下为
MemoryStream
),而
graph
MyObject[]
类型。 现在,ѭ1产生如下输出:
  <?xml version=\"1.0\" ?> 
  <ArrayOfMyObject xmlns:t=\"http://www.myproduct.com/2011/04/08/ArrayOfMyObject.xsd\">
  <MyObject>
  <LD>1</LD> 
  <SomeName>SOME CITY 04</SomeName> 
  <SomeNumber>04</SomeNumber> 
  </MyObject>
  <MyObject>
  <LD>1</LD> 
  <SomeName>SOME CITY 05</SomeName> 
  <SomeNumber>05</SomeNumber> 
  </MyObject>
  <MyObject>
  <LD>1</LD> 
  <SomeName>SOME CITY 07</SomeName> 
  <SomeNumber>07</SomeNumber> 
  </MyObject>
  <MyObject>
  <LD>18</LD> 
  <SomeName>BANKS-FREMONT</SomeName> 
  <SomeNumber>BF</SomeNumber> 
  </MyObject>
  <MyObject>
  <LD>18</LD> 
  <SomeName>BENNINGTON</SomeName> 
  <SomeNumber>B000</SomeNumber> 
  </MyObject>
  <MyObject>
  <LD>18</LD> 
  <SomeName>CENTER</SomeName> 
  <SomeNumber>CE</SomeNumber> 
  </MyObject>
  <MyObject>
  <LD>18</LD> 
  <SomeName>FRANKLINE MAXFIELD CITY</SomeName> 
  <SomeNumber>FR</SomeNumber> 
  </MyObject>
  <MyObject>
  <LD>18</LD> 
  <SomeName>FREDERIKA LEROY CITY OF</SomeName> 
  <SomeNumber>FD</SomeNumber> 
  </MyObject>
  <MyObject>
  <LD>18</LD> 
  <SomeName>HARLAN</SomeName> 
  <SomeNumber>HL</SomeNumber> 
  </MyObject>
  <MyObject>
  <CT>15</CT> 
  <SomeName>ATLANTIC 2 AND GROVE</SomeName> 
  <SomeNumber>AT2</SomeNumber> 
  </MyObject>
  <MyObject>
  <CT>15</CT> 
  <SomeName>BRIGHTON/MARNE/GROVE 1/P</SomeName> 
  <SomeNumber>MR</SomeNumber> 
  </MyObject>
  <MyObject>
  <CT>15</CT> 
  <SomeName>EDNA/NOBLE/PLEASANT/GRIS</SomeName> 
  <SomeNumber>GS</SomeNumber> 
  </MyObject>
  <MyObject>
  <CT>15</CT> 
  <SomeName>FRANKLIN/WIOTA/GRANT/ANI</SomeName> 
  <SomeNumber>AN</SomeNumber> 
  </MyObject>
  <MyObject>
  <CT>15</CT> 
  <SomeName>MASSENA AND CITY</SomeName> 
  <SomeNumber>MS</SomeNumber> 
  </MyObject>
  <MyObject>
  <CT>15</CT> 
  <SomeName>UNION &amp; CUMBERLAND</SomeName> 
  <SomeNumber>CU</SomeNumber> 
  </MyObject>
  <MyObject>
  <CD>3</CD> 
  <State>IA</State> 
  </MyObject>
  <MyObject>
  <CD>5</CD> 
  <State>IA</State> 
  </MyObject>
  <MyObject>
  <CT>1</CT> 
  <State>IA</State> 
  </MyObject>
  <MyObject>
  <CT>2</CT> 
  <State>IA</State> 
  </MyObject>
  <MyObject>
  <CT>5</CT> 
  <State>IA</State> 
  </MyObject>
  </ArrayOfMyObject>
当我呼叫
Context.SaveChanges
时,我得到一个异常,其内部异常消息为:   XML验证:找不到元素\'ArrayOfMyObject \'的声明。位置:/ *:ArrayOfMyObject [1] 我尝试使用许多不同的名称空间选项调用和/或创建序列化程序,但遇到相同的错误或类似的错误(提示应该是
{http://www.myproduct.com/2011/04/08/ArrayOfMyObject.xsd}ArrayOfMyObject
,但发现是
ArrayOfMyObject
,反之亦然)。 我需要更改什么,以便来自序列化器的XML将在SQL Server 2008上通过XML验证?     
已邀请:
我继续发布了这个问题,希望这个答案以后能对某人有所帮助,即使我实际上是想从XML验证中重现“类似”错误消息之一时也想出了答案。 可能还有其他方法可以使它起作用,但最终对我有用的是: 通过将
xmlns
更改为
xmlns:t
并添加
elementFormDefault=\"qualified\"
来更改XSD中的
xs:schema
元素:
<xs:schema id=\"ArrayOfMyObject\"
    targetNamespace=\"http://www.myproduct.com/2011/04/08/ArrayOfMyObject.xsd\"
    xmlns:t=\"http://www.myproduct.com/2011/04/08/ArrayOfMyObject.xsd\"
    xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"
    elementFormDefault=\"qualified\">
MyObject
类型的每个
xs:element
标签中添加
minOccurs=\"0\"
。我误解了此参考文档,是指将
xs:all
minOccurs=\"0\"
自动应用于其中的所有
xs:element
标签。如果那是正确的,则SQL Server似乎无法识别出它。因此,要通过验证,我必须使每个元素类似于
<xs:element name=\"CD\" type=\"xs:int\" minOccurs=\"0\" />
因为并非所有标签都将出现在每个“ 31”元素中。 在
ArrayOfMyObject
元素内的
MyObject
类型中添加名称空间前缀
t
<xs:element name=\"ArrayOfMyObject\">
    <xs:complexType>
        <xs:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">
            <xs:element name=\"MyObject\" type=\"t:MyObject\" />
        </xs:sequence>
    </xs:complexType>
</xs:element>
创建我的“ 1”时,同时使用类型和默认名称空间进行序列化和反序列化:
_xml = new XmlSerializer(typeof(MyObject[]), \"http://www.myproduct.com/2011/04/08/ArrayOfMyObject.xsd\");
我以前曾经尝试过,但是现在我知道这是最终解决方案的一部分。 呼叫
XmlSerializer.Serialize
时,请执行以下操作:
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(\"t\", \"http://www.myproduct.com/2011/04/08/ArrayOfMyObject.xsd\");
_xml.Serialize(serializationStream, graph, ns);
MyObject
类本身上,添加属性
[XmlRoot(Namespace=\"http://www.myproduct.com/2011/04/08/ArrayOfMyObject.xsd\")]
在序列化中包含的“ 31”的每个属性上,添加属性
[XmlElement(Namespace=\"http://www.myproduct.com/2011/04/08/ArrayOfMyObject.xsd\", Form=System.Xml.Schema.XmlSchemaForm.Qualified)]
最后,
MyObject
已经使用custom50ѭ实现了自定义序列化,而在我开始使用此功能时,
IXmlSerializable
已实现。这个事实可能使上面的属性添加变得不必要,但是我尚未测试该断言。无论哪种方式,都必须在
IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
方法中使用
writer.WriteElementString(name, \"http://www.myproduct.com/2011/04/08/ArrayOfMyObject.xsd\", propertyValue.ToString());
其中“ 54”是要序列化的属性的名称,“ 55”是其值。不必使用指定名称空间前缀的“ 56”形式;序列化程序会自动包含正确的前缀。
IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
方法已经使用
reader.LocalName
来检索元素名称,因此无需进行任何更改即可处理名称空间。 对不起,项目符号格式;列表似乎不能很好地与代码块配合使用。 希望这对某人在Google搜索中有所帮助。     

要回复问题请先登录注册