I have the following fairly simply XML that I'm trying to deserialize:
<props xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://foo.com/bar">
<prop name="foo1" xsi:type="xsd:string">bar1</prop>
<prop name="foo2" xsi:type="xsd:int">2</prop>
</props>
When I run XSD.exe over this XML to produce a schema and then run it again to produce C# classes, I end up with highly-decorated versions of the following:
public partial class props
{
[XmlElement("prop", IsNullable = true)]
propsProp[] Items { get; set; }
}
public partial class propsProp
{
[XmlAttribute]
public string name { get; set; }
[XmlText]
public string Value { get; set; }
}
Now when I try to deserialize the XML into these classes using XmlSerializer, I get the following exception:
System.InvalidOperationException: There is an error in XML document (4, 4). --->
System.InvalidOperationException: The specified type was not recognized: name='string', namespace='http://www.w3.org/2001/XMLSchema', at <prop xmlns='http://foo.com/bar'>.
The xsi:type
attribute is presumably there to facilitate some polymorphism on the prop
value, but I don't care about that - I just want the value in a C# property.
What am I doing wrong here? How can I get that XML into a C# class?
I went through exactly the same issue and it's solution is pretty straightforward for reference predefined type but a little bit tricky for primitive types.
First what is the benefit of using Using xsi:type
. I found this link is so helpful and it helps me solving the issue.
So we use xsi:type
in XML to refer to driven types, for example below:
<X xsi:type="X1">
Means that X and X1 are driven types from each others, So i fixed the deserialization by using inheritance, via creating a new class for the child type and make it inherit from the parent, also we need to create a list of it:
[XmlRoot(ElementName = "X1")]
public class X1: X
{
}
[XmlRoot(ElementName = "X1List")]
public class X1List
{
[XmlElement(ElementName = "X1")]
public X1 X1{ get; set; }
}
And in the other class which already uses X add also X1 as below:
[XmlRoot(ElementName = "Container")]
public class Container
{
...
[XmlElement(ElementName = "XList")]
public POCList XList{ get; set; }
[XmlElement(ElementName = "X1List")]
public X1List X1List{ get; set; }
...
[XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Xsi { get; set; }
}
This should solves the deserialization.
For primitive types it will be a tricky but you can achieve the same solution using generics with constrains.