Matthijs de Ridder
Matthijs de Ridder

Reputation: 303

Deserialize XML to same type childs on different elements

UPDATE: SOLVED - See below!

When deserializing a xml file containing network nodes there seem to go something wrong when handling child elements.

I've got the following parent (root) class: NetworkCollection

[Serializable, XmlRoot("networks"), XmlType("networks")]
public class NetworkCollection : CollectionBase, IBindingList
{
  // ...
}

With the child classes: Network

[Serializable, XmlRoot("network"), XmlType("network")]
public class Network
{
    [XmlAttribute("id")]
    public string Id { get; set; }

    [XmlElement("name")]
    public string Name { get; set; }

    // ...

    [XmlElement("nodes")]
    public NodeCollection Nodes { get; set; }

    [XmlElement("to_add")]
    public NodeCollection NodesToAdd { get; set; }

    [XmlElement("to_remove")]
    public NodeCollection NodesToRemove { get; set; }

    [XmlElement("available")]
    public NodeCollection NodesAvailable { get; set; }
}

Same for NodeCollection and Node

[Serializable, XmlRoot("nodes"), XmlType("nodes")]
public class NodeCollection : CollectionBase, IBindingList
{
    // ...
}

[Serializable, XmlRoot("node"), XmlType("node")]
public class Node
{
    [XmlAttribute("id")]
    public string Id { get; set; }

    [XmlElement("mac_address")]
    public string MacAddress { get; set; }
}

There are different node types, like this

[Serializable, XmlRoot("node_type_a"), XmlType("node_type_a")]
public class NodeTypeA : Node
{
    // ...
}

[Serializable, XmlRoot("node_type_b"), XmlType("node_type_b")]
public class NodeTypeB : Node
{
    // ...
}

[Serializable, XmlRoot("node_type_c"), XmlType("node_type_c")]
public class NodeTypeC : Node
{
    // ...
}

The XML looks like this

<?xml version="1.0" encoding="ISO-8859-1"?>
<networks>
  <network id="bcb468cac8a34052bf5a5bad8f22d0d7">
    <name>Network Name</name>
    <nodes>
      <node_type_a id="0ac4774277a941228b27d8cfd7ef202e">
        <mac_address>AABBCCDDEEFF</mac_address>
      </node_type_b>
      <node_type_a id="4ca5abb4bb8742c3b321250c20592542">
        <mac_address>BBCCDDEEFFAA</mac_address>
      </node_type_a>
      <node_type_b id="bde044c9aa1948978ba1bc980f00c36b">
        <mac_address>CCDDEEFFAABB</mac_address>
      </node_type_b>
      <node_type_c id="d3f2cb7bd92e4dc89930eeb3cdaeb680">
        <mac_address>DDEEFFAABBCC</mac_address>
      </node_type_c>
      <node_type_c id="039d140b5cc54e06b915b91fb5d8acdf">
        <mac_address>EEFFAABBCCDD</mac_address>
      </node_type_c>
    </nodes>
    <to_add/>
    <to_remove/>
    <available>
      <node>
        <mac_address>FFAABBCCDDEE</mac_address>
      </node>
      <node>
        <mac_address>001122334455</mac_address>
      </node>
      <node>
        <mac_address>112233445566</mac_address>
      </node>
      <node>
        <mac_address>223344556677</mac_address>
      </node>
    </available>
  </network>
</networks>

What happens is that every NodeCollection contains one element, so

Nodes (1),
NodesToAdd (1),
NodesToRemove (1) and
NodesAvailable (1)

all contain one Node object with it's property (MacAddress) set to null;

This should be

Nodes (5),
NodesToAdd (0),
NodesToRemove (0) and
NodesAvailable (4)

Deserializing the NetworkCollection and Network works fine. It's just about the NodeCollection properties.

Please note the used XmlRoot and XmlType attributes. The "Id" of the available nodes might be null / missing.

How to deal with this? Regards


OK, i've solved the problem by replacing

[XmlElement("nodes")]
public NodeCollection Nodes { get; set; }

[XmlElement("to_add")]
public NodeCollection NodesToAdd { get; set; }

[XmlElement("to_remove")]
public NodeCollection NodesToRemove { get; set; }

[XmlElement("available")]
public NodeCollection NodesAvailable { get; set; }

With

[XmlArray("nodes")]
[XmlArrayItem(ElementName = "node", Type = typeof(Node))]
[XmlArrayItem(ElementName = "node_type_a", Type = typeof(NodeTypeA))]
[XmlArrayItem(ElementName = "node_type_b", Type = typeof(NodeTypeB))]
[XmlArrayItem(ElementName = "node_type_c", Type = typeof(NodeTypeC))]
public NodeCollection Nodes { get; set; }

[XmlArray("to_add")]
[XmlArrayItem(ElementName = "node", Type = typeof(Node))]
[XmlArrayItem(ElementName = "node_type_a", Type = typeof(NodeTypeA))]
[XmlArrayItem(ElementName = "node_type_b", Type = typeof(NodeTypeB))]
[XmlArrayItem(ElementName = "node_type_c", Type = typeof(NodeTypeC))]
public NodeCollection NodesToAdd { get; set; }

[XmlArray("to_remove")]
[XmlArrayItem(ElementName = "node", Type = typeof(Node))]
[XmlArrayItem(ElementName = "node_type_a", Type = typeof(NodeTypeA))]
[XmlArrayItem(ElementName = "node_type_b", Type = typeof(NodeTypeB))]
[XmlArrayItem(ElementName = "node_type_c", Type = typeof(NodeTypeC))]
public NodeCollection NodesToRemove { get; set; }

[XmlArray("available")]
[XmlArrayItem(ElementName = "node", Type = typeof(Node))]
[XmlArrayItem(ElementName = "node_type_a", Type = typeof(NodeTypeA))]
[XmlArrayItem(ElementName = "node_type_b", Type = typeof(NodeTypeB))]
[XmlArrayItem(ElementName = "node_type_c", Type = typeof(NodeTypeC))]
public NodeCollection NodesAvailable { get; set; }

Regards.

Upvotes: 3

Views: 1777

Answers (1)

Matthijs de Ridder
Matthijs de Ridder

Reputation: 303

OK, i've solved the problem by replacing

[XmlElement("nodes")]
public NodeCollection Nodes { get; set; }

[XmlElement("to_add")]
public NodeCollection NodesToAdd { get; set; }

[XmlElement("to_remove")]
public NodeCollection NodesToRemove { get; set; }

[XmlElement("available")]
public NodeCollection NodesAvailable { get; set; }

With

[XmlArray("nodes")]
[XmlArrayItem(ElementName = "node", Type = typeof(Node))]
[XmlArrayItem(ElementName = "node_type_a", Type = typeof(NodeTypeA))]
[XmlArrayItem(ElementName = "node_type_b", Type = typeof(NodeTypeB))]
[XmlArrayItem(ElementName = "node_type_c", Type = typeof(NodeTypeC))]
public NodeCollection Nodes { get; set; }

[XmlArray("to_add")]
[XmlArrayItem(ElementName = "node", Type = typeof(Node))]
[XmlArrayItem(ElementName = "node_type_a", Type = typeof(NodeTypeA))]
[XmlArrayItem(ElementName = "node_type_b", Type = typeof(NodeTypeB))]
[XmlArrayItem(ElementName = "node_type_c", Type = typeof(NodeTypeC))]
public NodeCollection NodesToAdd { get; set; }

[XmlArray("to_remove")]
[XmlArrayItem(ElementName = "node", Type = typeof(Node))]
[XmlArrayItem(ElementName = "node_type_a", Type = typeof(NodeTypeA))]
[XmlArrayItem(ElementName = "node_type_b", Type = typeof(NodeTypeB))]
[XmlArrayItem(ElementName = "node_type_c", Type = typeof(NodeTypeC))]
public NodeCollection NodesToRemove { get; set; }

[XmlArray("available")]
[XmlArrayItem(ElementName = "node", Type = typeof(Node))]
[XmlArrayItem(ElementName = "node_type_a", Type = typeof(NodeTypeA))]
[XmlArrayItem(ElementName = "node_type_b", Type = typeof(NodeTypeB))]
[XmlArrayItem(ElementName = "node_type_c", Type = typeof(NodeTypeC))]
public NodeCollection NodesAvailable { get; set; }

Regards.

Upvotes: 2

Related Questions