I have this class definition
public class Foo
{
}
Which deserializes into this xml
<?xml version="1.0"?>
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
</Foo>
This xml file layout already exists on client machines.
I want to rename the class from Foo
to Footastic
.
public class Footastic
{
}
Any new serialize of the now called class Footastic
, should serialize as
<?xml version="1.0"?>
<Footastic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
</Footastic>
My question is how can I tell the deserialization to accept either Foo
or Footastic
?
I know I could "rename" the Footastic
to Foo
by specifing the XmlRoot
attribute.
[XmlRoot("Foo")]
public class Footastic
{
}
BUT this would also change any new serialization of the object, this is undesired.
A new serialization should serialize as Footastic
ONLY old xml files containing the old name Foo
should be supported while deserializing Footastic
.
Just in case you need the code for deserializing/serializing. I am not really doing anything fancy.
Deserialize:
public static T? Deserialize<T>(string fileName)
{
if (!File.Exists(fileName))
return default;
using FileStream streamReader = new(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using var xr = XmlReader.Create(streamReader);
XmlSerializer xmlDeSerializer = new(typeof(T));
return (T?)xmlDeSerializer.Deserialize(xr);
}
Serialize:
public static void Serialize<T>(T? value, string fileName)
{
if (value is null)
return;
Directory.CreateDirectory(Path.GetDirectoryName(fileName) ?? "");
using FileStream fileStream = new(fileName, FileMode.Create, FileAccess.Write, FileShare.Write);
using var streamWriter = XmlWriter.Create(fileStream, new()
{
Encoding = Encoding.UTF8,
Indent = true
});
XmlSerializer xmlSerializer = new(typeof(T));
xmlSerializer.Serialize(streamWriter, value);
}
Try the following approach.
Create a custom XML reader that replaces the name Foo
with Footastic
on the fly.
public class FooReader : XmlTextReader
{
// Add other constructor overloads as needed.
public FooReader(string url) : base(url) { }
public override string LocalName
{
get
{
if (base.LocalName == "Foo")
return "Footastic";
return base.LocalName;
}
}
}
Use it like this.
var ser = new XmlSerializer(typeof(Footastic));
using var fooReader = new FooReader("test.xml");
var foo = (Footastic)ser.Deserialize(fooReader);
This will accept both Foo
and Footastic
.
However, be careful! This will replace all Foo elements!
If you have elements with the same name in xml in other places, then you need to make additional checks.