I have a class which I would like to serialize. However, this class implements IEnumerator, so I have to make it IXmlSerializable. My class looks like this:
public class Pipeline : IEnumerator<Node>, IEnumerable<Node>, IXmlSerializable
{
public string Name { get; set; }
public List<Trigger> triggers;
public Node root;
//Methods...
}
The WriteXml-method I came up with is quite straight forward and writes the object (Pipeline), which is representing nodes, some metadata (name, id, etc.) and the edges between the nodes as a file:
public void WriteXml(XmlWriter writer)
{
writer.WriteAttributeString("Name", Name);
List<Node> nod = new List<Node>(this);
var ser1 = new XmlSerializer(typeof(List<Node>), GetLoadedTypes().ToArray());
ser1.Serialize(writer, nod);
var ser2 = new XmlSerializer(typeof(List<Edge>));
ser2.Serialize(writer, GetEdges());
}
The produced XML-file looks ok to me:
<?xml version="1.0" encoding="utf-8"?>
<Pipeline Name="TestPipeline">
<ArrayOfNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Node xsi:type="TestTrigger" ID="63248778" Name="yesyes" />
<Node xsi:type="Do" ID="32368095">
<variables>
<string>hello</string>
</variables>
<Actions>x => Console.WriteLine($"{x}")</Actions>
</Node>
</ArrayOfNode>
<ArrayOfEdge xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Edge From="63248778" To="32368095" />
<Edge From="32368095" To="" />
</ArrayOfEdge>
</Pipeline>
But now my troubles are starting: How should the ReadXML-method looks like? What I came up with, ends in the error InvalidOperationException: <Pipeline xmlns=''> was not expected.
in the line Node[] nods = (Node[])ser1.Deserialize(reader);
.
public void ReadXml(XmlReader reader)
{
Name = reader.GetAttribute("Name");
var ser1 = new XmlSerializer(typeof(Node[]));
Node[] nods = (Node[])ser1.Deserialize(reader);
//-- load the Edges as well
}
Because the two arrays are quit complex (list of derivatives of Node) and their fields can change in future, I don't want to do this by reading it elementwise and cast it to my the needed objects.
What is the correct solution to read the XML-File again?
As György pointed out in his comment, the missing part was the Read
/MoveTo
-Command. Here a working example with a nested XmlSerializer
:
public void ReadXml(XmlReader reader)
{
Name = reader.GetAttribute("Name");
reader.Read(); // Check if read was successful
var ser1 = new XmlSerializer(typeof(Node[]), Utils.Utils.GetNodeTypes());
Node[] nods = (Node[])ser1.Deserialize(reader);
var ser2 = new XmlSerializer(typeof(Edge[]), new Type[] { typeof(Edge) });
Edge[] edges = (Edge[])ser2.Deserialize(reader);
// Do something with your elements
}