I have the following XML
<?xml version="1.0" encoding="UTF-16" standalone="no"?>
<Sites>
<Site>
<Code>TWTR</Code>
<Name>twitter.com</Name>
</Site>
<Site>
<Code>FB</Code>
<Name>facebook.com</Name>
</Site>
<Site>
<Code>SO</Code>
<Name>stackoverflow.com</Name>
</Site>
</Sites>
This is the code:
public class Program
{
static void Main(string[] args)
{
var fs = new FileStream(@"D:\temp\Sites.xml", FileMode.Open);
var serializer = new XmlSerializer(typeof(List<Site>));
var instance = (List<Site>)serializer.Deserialize(fs);
}
}
[XmlRoot("Sites")]
public class Site
{
public string Code { get; set; }
public string Name { get; set; }
}
The exception I get is: <Sites xmlns=''> was not expected.
. The reason for this error is usually, when I don't define an XmlRoot for the XmlSerializer
. But as you can see, I did that by decorating the class Site
with the XmlRootAttribute
To complete my confusion, the following trick works:
Replace
var serializer = new XmlSerializer(typeof(List<Site>));
with
var serializer = new XmlSerializer(typeof(List<Site>), new XmlRootAttribute("Sites"));
Am I missing something?
If you have control over the XML, then simply change:
<Sites>
To
<ArrayOfSite xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
If you don't have control over the XML, create your own collection and deserialize into that.
[XmlRoot("Sites")]
public class Sites : List<Site>
{
}
Be careful when using the following constructor:
var serializer = new XmlSerializer(typeof(List<Site>), new XmlRootAttribute("Sites"));
As Microsoft points out here, if you don't cache the instance of the serializer associated with List<Site>
, you will end up with leaky memory...
Dynamically Generated Assemblies
To increase performance, the XML serialization infrastructure dynamically generates assemblies to serialize and deserialize specified types. The infrastructure finds and reuses those assemblies. This behavior occurs only when using the following constructors:
XmlSerializer.XmlSerializer(Type)
XmlSerializer.XmlSerializer(Type, String)
If you use any of the other constructors, multiple versions of the same assembly are generated and never unloaded, which results in a memory leak and poor performance. The easiest solution is to use one of the previously mentioned two constructors. Otherwise, you must cache the assemblies in a Hashtable, as shown in the following example.
The XmlRoot
attribute you added to Site
is not used, because you aren't deserializing an object of type Site
. You are deserializing an object of type List<Site>
and that's where the serializer looks for the XmlRoot
attribute.
Your workaround actually is the correct solution. However, if you are performing this deserialization often in your program, be sure to cache the XmlSerializer
instance, because that specific constructor doesn't internally cache the dynamically generated assemblies - this contrasts with the constructor you normally use.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With