xmlxml-serializationxmlserializerxmltype

XML Deserialization of xsi:type="array"


I need to replicate this XML structure with class instances but I am failing on the xmlAttribute xsi:type="array"

This is my plain class setup, I tried a hundred things from various posts and tutorials like XmlInclude but i can't seem to make it work:

private ST_DtxInstance dtxFile = new ST_DtxInstance();
                
[System.Xml.Serialization.XmlRootAttribute(ElementName = "Database", Namespace = "http://www.staubli.com/robotics/VAL3/Data/2", IsNullable = false)]
public class ST_DtxInstance
{
    [XmlArray("Datas")]
    [XmlArrayItem("Data")]
    public ST_Data[] csDatas = new ST_Data[] { new ST_Data(), new ST_Data() };
}

public class ST_Data
{
    [XmlElement("Value")]
    public ST_Value value = new ST_Value();

    [XmlAttribute("name")]
    public string csName = "Name";
            
    [XmlAttribute("access")]
    public string csAccess = "public";

    [XmlAttribute(AttributeName = "type", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
    public string xsi_xmlType = "array";

    [XmlAttribute("type")]
    public string csType = "NA";

    [XmlAttribute("size")]
    public string csSize = "-1";
}

public class ST_Field
{
    [XmlElement("Value")]
    public ST_Value csValue = new ST_Value();

    [XmlAttribute("name")]
    public string csName = "Name of Type";

    [XmlAttribute(AttributeName = "type", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
    public string xsi_xmlType = "array"; //always array

    [XmlAttribute("type")]
    public string csType = "NA";

    [XmlAttribute("size")]
    public string csSize = "1";
}

public class ST_Value
{
    [XmlArrayItem(ElementName = "Field")]
    public ST_Field[] csDatas = null;

    [XmlAttribute(AttributeName = "key")]
    public int csKey = -1;
    [XmlAttribute(AttributeName = "link")]
    public string csLink = "NA";
}

private ST_DtxInstance DeserializeDTX(string xmlPath)
{
    DisplayFile(xmlPath);

    XmlSerializer serializer = new XmlSerializer(typeof(ST_DtxInstance));
    var fileReader = new FileStream(xmlPath, FileMode.Open);
    var result = (ST_DtxInstance)serializer.Deserialize(fileReader);
    fileReader.Close();

    return result;
}

private void SerializeDTX(ST_DtxInstance instance, string xmlPath)
{
    XmlSerializer serializer = new XmlSerializer(typeof(ST_DtxInstance));
    TextWriter fileWriter = new StreamWriter(xmlPath);

    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
    ns.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");

    serializer.Serialize(fileWriter, instance, ns);
    fileWriter.Close();

    DisplayFile(xmlPath);
}

private void DisplayFile(string path)
{
    labl.Content = File.ReadAllText(path);
}

And this is the XML-format want to read and write

<Database xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.staubli.com/robotics/VAL3/Data/2">
  <Datas>
    <Data name="Nodes" access="public" **xsi:type="array"** type="Node" size="100">
      <Value key="0">
        <Field name="Id" **xsi:type="array"** type="num" size="1">
          <Value key="0" value="15" />
        </Field>
        <Field name="Lock" xsi:type="array" type="string" size="1">
          <Value key="0" value="NO " />
        </Field>
        <Field name="Name" xsi:type="array" type="string" size="1">
          <Value key="0" value="BasePosition" />
        </Field>
        <Field name="EdgeInstance" xsi:type="array" type="Edge" size="2">
          <Value key="0">
            <Field name="CurrentSequencnumber" xsi:type="array" type="num" size="1">
              <Value key="0" value="13" />
            </Field>
            <Field name="CurrentWeight" xsi:type="array" type="num" size="1">
              <Value key="0" value="90000" />
            </Field>
            <Field name="IdEnd" xsi:type="array" type="num" size="1" />
            <Field name="IdStart" xsi:type="array" type="num" size="1" />
            <Field name="Lenght" xsi:type="array" type="num" size="1" />
            <Field name="SpeedLimit" xsi:type="array" type="num" size="1">
              <Value key="0" value="30" />
            </Field>
          </Value>
          <Value key="1">
            <Field name="CurrentSequencnumber" xsi:type="array" type="num" size="1" />
            <Field name="CurrentWeight" xsi:type="array" type="num" size="1" />
            <Field name="IdEnd" xsi:type="array" type="num" size="1" />
            <Field name="IdStart" xsi:type="array" type="num" size="1" />
            <Field name="Lenght" xsi:type="array" type="num" size="1" />
            <Field name="SpeedLimit" xsi:type="array" type="num" size="1" />
          </Value>
        </Field>
      </Value>
      <Value key="1">
        <Field name="Id" xsi:type="array" type="num" size="1" />
        <Field name="Lock" xsi:type="array" type="string" size="1" />
        <Field name="Name" xsi:type="array" type="string" size="1" />
        <Field name="EdgeInstance" xsi:type="array" type="Edge" size="2">
          <Value key="0">
            <Field name="CurrentSequencnumber" xsi:type="array" type="num" size="1" />
            <Field name="CurrentWeight" xsi:type="array" type="num" size="1" />
            <Field name="IdEnd" xsi:type="array" type="num" size="1" />
            <Field name="IdStart" xsi:type="array" type="num" size="1" />
            <Field name="Lenght" xsi:type="array" type="num" size="1" />
            <Field name="SpeedLimit" xsi:type="array" type="num" size="1" />
          </Value>
          <Value key="1">
            <Field name="CurrentSequencnumber" xsi:type="array" type="num" size="1" />
            <Field name="CurrentWeight" xsi:type="array" type="num" size="1" />
            <Field name="IdEnd" xsi:type="array" type="num" size="1" />
            <Field name="IdStart" xsi:type="array" type="num" size="1" />
            <Field name="Lenght" xsi:type="array" type="num" size="1" />
            <Field name="SpeedLimit" xsi:type="array" type="num" size="1" />
          </Value>
        </Field>
      </Value>
    </Data>
  </Datas>
</Database>

Also, occasionally there might also be an xsi:type="collection" instead of an "array" on some elements within the same array.


Solution

  • I got it working by serializing data and getting serialize output to match input

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using System.Xml.Serialization;
    
    namespace ConsoleApplication23
    {
    
        class Program
        {
            const string INPUT_FILENAME = @"c:\temp\test.xml";
            const string OUTPUT_FILENAME = @"c:\temp\test1.xml";
            static void Main(string[] args)
            {
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                ns.Add("", "http://www.staubli.com/robotics/VAL3/Data/2");
                ns.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
    
                XmlReader reader = XmlReader.Create(INPUT_FILENAME);
                XmlSerializer serializer = new XmlSerializer(typeof(Database));
                Database database = (Database)serializer.Deserialize(reader);
    
                Database database1 = new Database();
                database1.data = new List<Data>();
                array data = new array();
                database1.data.Add(data);
                data.name = "Nodes";
                data.access = "public";
                data.type = "Node";
                data.size = 100;
                data.values = new List<Value>();
                Value value = new Value();
                data.values.Add(value);
                value.fields = new List<Data>();
                array array1 = new array();
                value.fields.Add(array1);
    
    
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Indent = true;
                XmlWriter writer = XmlWriter.Create(OUTPUT_FILENAME, settings);
                serializer.Serialize(writer, database1, ns);
    
    
            }
        }
        [XmlRoot(ElementName = "Database", Namespace = "http://www.staubli.com/robotics/VAL3/Data/2")]
        
        public class Database
        {
            [XmlArray(ElementName = "Datas", Namespace = "http://www.staubli.com/robotics/VAL3/Data/2")]
            [XmlArrayItem(ElementName = "Data", Namespace = "http://www.staubli.com/robotics/VAL3/Data/2")]
            public List<Data> data { get; set; }
    
        }
        [XmlInclude(typeof(array))]
        public class Data
        {
            [XmlAttribute]
            public string name { get; set; }
            [XmlAttribute]
            public string access { get; set; }
            [XmlAttribute]
            public string type { get; set; }
            [XmlAttribute]
            public int size { get; set; }
        }
        [XmlRoot(ElementName = "array", Namespace = "http://www.staubli.com/robotics/VAL3/Data/2")]
        public class array : Data 
        {
            [XmlElement(ElementName = "Value", Namespace = "http://www.staubli.com/robotics/VAL3/Data/2")]
            public List<Value> values { get; set; } 
        }
        public class Value
        {
            [XmlAttribute]
            public int key { get; set; }
            [XmlElement(ElementName = "Field", Namespace = "http://www.staubli.com/robotics/VAL3/Data/2")]
            public List<Data> fields { get; set; }
        }
      
    }