Search code examples
c#xmldatatablexsddataset

Preserving order of elements when converting XSD to Dataset to XML


I am loading an XSD file into an empty dataset, loading data into the dataset, and then writing an XML file with that dataset.

The problem is if the XSD has a sequence type that contains a mixture of simple types and complex types in random order. The XML generated will always create the simple types first (based on the table columns) and then the complex types (based on the child rows of the data table), which is of course failing validation against a sequence type.

Here is an example:

       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();

This returns the following 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>

How can I preserve the order of the elements to satisfy the XSD validation?


Solution

  • I managed to solve it by writing my own custom converter class that uses the xsd as a reference to generate the final xml. Something similar to this:

    public class DataSetToSchemaBasedXmlConverter : IConvert<DataSet, XmlDocument>
    {
        private readonly XmlSchema _schema;
    
        public DataSetToSchemaBasedXmlConverter(XmlSchema schema)
        {
            _schema = schema;
        }
    
        public XmlDocument Convert(DataSet dataSet)
        {
            var doc = new XmlDocument();
    
            // Traverse through xsd elements and create corresponding 
            // xml elements based on the dataset values.
    
            return doc;
        }
    }