我将 XSD 文件加载到空数据集中,将数据加载到数据集中,然后使用该数据集编写 XML 文件。
问题是 XSD 的序列类型是否包含随机顺序的简单类型和复杂类型的混合。生成的 XML 将始终首先创建简单类型(基于表列),然后创建复杂类型(基于数据表的子行),这当然无法针对序列类型进行验证。
这是一个例子:
var schemaString = @"<xs:schema xmlns:xs=""http://www.w3.org/2001/XMLSchema"" >
<xs:element name=""Person"">
<xs:complexType>
<xs:sequence>
<xs:element name=""Ttl"" minOccurs=""0"">
<xs:simpleType>
<xs:restriction base=""xs:string"">
<xs:maxLength value=""4"" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element minOccurs=""0"" maxOccurs=""1"" name=""Address"">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs=""1"" maxOccurs=""4"" name=""Line_1"">
<xs:simpleType>
<xs:restriction base=""xs:string"">
<xs:maxLength value=""35"" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element minOccurs=""1"" maxOccurs=""4"" name=""Line_2"">
<xs:simpleType>
<xs:restriction base=""xs:string"">
<xs:maxLength value=""35"" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element minOccurs=""0"" maxOccurs=""1"" name=""PostCode"">
<xs:simpleType>
<xs:restriction base=""xs:string"">
<xs:maxLength value=""35"" />
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name=""Fore"" maxOccurs=""2"">
<xs:simpleType>
<xs:restriction base=""xs:string"">
<xs:maxLength value=""35"" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name=""Sur"">
<xs:simpleType>
<xs:restriction base=""xs:string"">
<xs:maxLength value=""35"" />
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>";
var schemaReader = XmlReader.Create(new StringReader(schemaString));
var dataSet = new DataSet();
dataSet.ReadXmlSchema(schemaReader);
dataSet.Tables["Person"].Rows.Add("Mr", "John", "Smith");
dataSet.Tables["Address"].Rows.Add("Street", "Suburb", "1234");
dataSet.Tables["Address"].Rows[0].SetParentRow(dataSet.Tables["Person"].Rows[0]);
return dataSet.GetXml();
这将返回以下 XML:
<NewDataSet>
<Person>
<Ttl>Mr</Ttl>
<Fore>John</Fore>
<Sur>Smith</Sur>
<Address>
<Line_1>Street</Line_1>
<Line_2>Suburb</Line_2>
<PostCode>1234</PostCode>
</Address>
</Person>
</NewDataSet>
如何保留元素的顺序以满足 XSD 验证?
因此,我相当有信心使用 .NET 中的
DataSet
类来保留模式定义的元素排序是不可能的。
根据 Microsoft 的说法,从此页面:
...如果使用 ReadXml 从 XML 文档填充数据集,则当使用
将数据作为 XML 文档写回时,它可能与原始 XML 文档有很大不同。 这是因为 DataSet 不维护 XML 文档中的格式(例如空格)或层次结构信息(例如元素顺序)。 DataSet 也不包含 XML 文档中因不匹配而被忽略的元素数据集的架构。WriteXml
我已将相关句子加粗。如果您还反编译
WriteXml()
类的 GetXml()
和 DataSet
方法(因为您使用的是 GetXml()
),它们都使用相同的内部 XmlDataTreeWriter
类来写入输出 XML,因此推测上述内容适用也适合你的情况。上面的文档页面还提到,人们应该更喜欢使用 XmlDataDocument
,但请记住,这是一个已弃用的类。
另外关于你问题的第一部分:
我将 XSD 文件加载到空数据集中,将数据加载到数据集中,然后使用该数据集编写 XML 文件。
如果仅此而已,我建议您使用提前生成 C# 模型类的代码生成策略,因为您已经有了 XML 架构。
像 LinqToXsd 这样的工具(这是他们开源的 Microsoft 编写的工具)将采用架构并生成 C# 类,然后您可以对其进行编程(它与 .NET Core/.NET 和 .NET Framework 兼容) 。我尝试将它用于您的模式,并最终得到这样的代码(我省略了生成的代码,因为它对于 SO 帖子来说太长了):
var p = new Person();
p.Ttl = "Mr";
p.Fore.Add("John");
p.Sur = "Smith";
p.Address = new Default.Person.AddressLocalType()
{
Line_1 = { "Street 1" },
Line_2 = { "Suburb" }
};
请注意,对 set
Address
的调用是 C# 代码中的最后一个,但是当您通过调用 p.ToString()
将其转换回 XML 时,它将保留模式中定义的顺序(即 Address
作为元素 2 在Person
元素):
<Person>
<Ttl>Mr</Ttl>
<Address>
<Line_1>Street 1</Line_1>
<Line_2>Suburb</Line_2>
</Address>
<Fore>John</Fore>
<Sur>Smith</Sur>
</Person>
我建议使用
LinqToXsd
,因为它比 xsd.exe 对复杂类型有更好的支持。当然,除非出于遗留原因您别无选择,只能使用 DataSet
。