简体   繁体   中英

C#/.net Preserve Schema and XML when calling XMLWriter() function from dataset

I have an xml file

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfLocations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Location xsi:type="JointLocation">
    <Name>Example Location</Name>
    <Index>0</Index>
    <ZClearance>0</ZClearance>
    <Joint1>100</Joint1>
    <Joint2>200</Joint2>
    <Joint3>200</Joint3>
    <Joint4>200</Joint4>
    <Joint5>200</Joint5>
    <joint6>0</joint6>
    <Joint6>0</Joint6>
  </Location>
</ArrayOfLocations>

I load this file into a data set, and then into a DataGridView. From that DataGridView I can add new Location elements, or edit existing Location elements and save. When I save, I am doing this

string path = filePathBox.Text;
DataSet ds = (DataSet)dataGridView1.DataSource;
ds.WriteXml(filePathBox.Text);

After saving, the XML file then looks like

<?xml version="1.0" standalone="yes"?>
<ArrayOfLocations>
  <Location>
    <Name>Example Location</Name>
    <Index>0</Index>
    <ZClearance>0</ZClearance>
    <Joint1>100</Joint1>
    <Joint2>200</Joint2>
    <Joint3>200</Joint3>
    <Joint4>200</Joint4>
    <Joint5>200</Joint5>
    <joint6>0</joint6>
    <Joint6>0</Joint6>
  </Location>
</ArrayOfLocations>

As you can see the xsi and namespace have been removed. I would like to preserve these attributes.

So far I have tried adding as an additional parameter to WriteXML():

ds.WriteXML(filepath, XmlWriteMode.WriteSchema)

However, this creates a big mess and still does not maintain the initial format that I want to preserve. Any tips?

A simple example shows us that ReadXML / WriteXML will lose the schema info you're interested in

using (FileStream fs = new FileStream("D:\\Workspace\\FormTest\\input.xml", FileMode.Open))
{
    DataSet ds = new DataSet();
    ds.ReadXml(fs);
    ds.WriteXml(Console.Out);
}

Gives us

<ArrayOfLocations>
  <Location>
    <Name>Example Location</Name>
    <Index>0</Index>
    <ZClearance>0</ZClearance>
    <Joint1>100</Joint1>
    <Joint2>200</Joint2>
    <Joint3>200</Joint3>
    <Joint4>200</Joint4>
    <Joint5>200</Joint5>
    <joint6>0</joint6>
    <Joint6>0</Joint6>
  </Location>
</ArrayOfLocations>

The best way I found to recover this schema information is to Deserialize the data. It's not pretty but it worked for me:

XmlSerializer s = new XmlSerializer(typeof(ArrayOfLocations));
ArrayOfLocations fix = new ArrayOfLocations();
using (FileStream fs = new FileStream("D:\\Workspace\\FormTest\\input.xml", FileMode.Open))
{
    DataSet ds = new DataSet();
    ds.ReadXml(fs);
    string xml = ds.GetXml();
    ArrayOfLocations input = (ArrayOfLocations)s.Deserialize(new StringReader(xml));
    
    foreach(var location in input)
    {
        fix.Add(new JointLocation()
        {
            Name = location.Name,
            ...
            Joint6 = location.Joint6 
        });
    }
}

XmlTextWriter xtw = new XmlTextWriter(Console.Out);
xtw.Formatting = Formatting.Indented;
s.Serialize(xtw, fix);

And of course you'll need to create the classes that model your schema in order to deserialize:

public class Location
{
    public string Name { get; set; }
    ...
    public byte Joint6 { get; set; }
}

public class JointLocation : Location { }

[XmlInclude(typeof(JointLocation))]
[XmlRoot("ArrayOfLocations")]
public class ArrayOfLocations : List<Location> { }

Note the following gotchas

  1. You need to define a JoinLocation class, specify that type under XmlInclude , and manually fix your object all in order to comply with the schema that you want to output to.
  2. You will need to use a XmlTextWritter to respect indentation

This all should give you the desired output:

<?xml version="1.0" encoding="Codepage - 437"?>
<ArrayOfLocations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Location xsi:type="JointLocation">
    <Name>Example Location</Name>
    <Index>0</Index>
    <ZClearance>0</ZClearance>
    <Joint1>100</Joint1>
    <Joint2>200</Joint2>
    <Joint3>200</Joint3>
    <Joint4>200</Joint4>
    <Joint5>200</Joint5>
    <Joint6>0</Joint6>
  </Location>
</ArrayOfLocations>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM