Reputation: 373
I have many .xsd files for many xml schemas
example
XML 1.0 - xml_1_0.xml
<?xml version="1.0" encoding="UTF-8"?>
<cars version="1.00">
<car>Honda</car>
<car>Ferrari</car>
</cars>
XML 2.0 - xml_2_0.xml
<?xml version="1.0" encoding="UTF-8"?>
<cars version="2.00">
<car>
<name>Honda</name>
<color>White</color>
</car>
<car>
<name>Honda</name>
<color>Red</color>
</car>
</cars>
I create my classes from .xsd like this
xsd.exe cars_1_0.xsd /c
xsd.exe cars_2_0.xsd /c
And Deserialize like this:
foreach(string file in files) {
XmlDocument doc = new XmlDocument();
doc.Load(file);
string version = doc.SelectSingleNode("/Cars/@version").Value;
if(version == "1.00")
{
Stream reader = new FileStream(file, FileMode.Open);
XmlSerializer serializer = new XmlSerializer(typeof(v1.Cars));
v1.Cars XML = new v1.Cars();
XML = (v1.Cars)serializer.Deserialize(reader);
}
else if(version == "2.00")
{
Stream reader = new FileStream(file, FileMode.Open);
XmlSerializer serializer = new XmlSerializer(typeof(v2.Cars));
v2.Cars XML = new v2.Cars();
XML = (v2.Cars)serializer.Deserialize(reader);
}
}
Does anyone know a better way to do this, or have a better performance?
Upvotes: 2
Views: 119
Reputation: 21661
You have several options, depending on how far you want to take this. One fairly non invasive option would be to not use XmlDocument
and avoid loading the stream more than once. For example, your existing code could be simplified/streamlined to :
foreach (string file in files)
{
using (var stream = new FileStream(file, FileMode.Open))
{
var settings = new XmlReaderSettings();
settings.CloseInput = false;
string version = "";
using (var xmlReader = XmlReader.Create(stream))
{
if (xmlReader.ReadToFollowing("Cars"))
{
version = xmlReader.GetAttribute("version");
}
else
{
throw new XmlException("Could not get 'version' attribute of 'Cars' root element!");
}
}
stream.Position = 0;
if (version == "1.00")
{
XmlSerializer serializer = new XmlSerializer(typeof(v1.Cars));
v1.Cars XML = new v1.Cars();
XML = (v1.Cars)serializer.Deserialize(stream);
}
else if (version == "2.00")
{
XmlSerializer serializer = new XmlSerializer(typeof(v2.Cars));
v2.Cars XML = new v2.Cars();
XML = (v2.Cars)serializer.Deserialize(stream);
}
}
}
Since you're just reading off the root element, you might even be able to get away with deserializing from the XmlReader
and not have to reset the position on the FileStream
.
This avoids the overhead of loading the entire file twice (once for XmlDocument
, then again for XmlSerializer
) - and particularly avoids the memory overhead of creating a DOM for each document.
A more nuclear option would be implementing IXmlSerializable
on a set of custom classes, which would have custom logic in the ReadXml
methods to parse the version attribute and instantiate the correct child type(s) - e.g. a CarCollection
class that has a List<Car>
property, where Car
is an abstract class that has CarV1
and CarV2
as descendants. This would be about as efficient as you could get (and offer very fine grained control over your class hierarchy design), but would eliminate the possibility of using xsd.exe to generate your classes.
Upvotes: 1