将 XSD 转换为数据集再转换为 XML 时保留元素顺序

问题描述 投票:0回答:1

我将 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 验证?

c# xml datatable xsd dataset
1个回答
0
投票

因此,我相当有信心使用 .NET 中的

DataSet
类来保留模式定义的元素排序是不可能的。

根据 Microsoft 的说法,从此页面

...如果使用 ReadXml 从 XML 文档填充数据集,则当使用

WriteXml
将数据作为 XML 文档写回时,它可能与原始 XML 文档有很大不同。 这是因为 DataSet 不维护 XML 文档中的格式(例如空格)或层次结构信息(例如元素顺序)。 DataSet 也不包含 XML 文档中因不匹配而被忽略的元素数据集的架构。

我已将相关句子加粗。如果您还反编译

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

© www.soinside.com 2019 - 2024. All rights reserved.