如何使XmlSerializer与xsi:type一起使用?

时间:2012-05-16 15:34:48

标签: .net xml-serialization xmlserializer

我有以下相当简单的XML,我正在尝试反序列化:

<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>

当我在这个XML上运行XSD.exe以生成一个模式然后再次运行它来生成C#类时,我最终会得到以下高度装饰的版本:

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; }
}

现在,当我尝试使用XmlSerializer将XML反序列化为这些类时,我得到以下异常:

  

System.InvalidOperationException:XML文档中存在错误(4,4)。 ---&gt;
System.InvalidOperationException:无法识别指定的类型:name ='string',namespace ='http://www.w3.org/2001/XMLSchema',at&lt; prop xmlns = “http://foo.com/bar'> ;.

xsi:type属性可能是为了促进prop值的某些多态性,但我并不关心 - 我只想要C#属性中的值。

我在这里做错了什么?如何将XML转换为C#类?

1 个答案:

答案 0 :(得分:0)

我经历了完全相同的问题,对于引用预定义类型,它的解决方案非常简单,但对于原始类型,它的解决方案有些棘手。

首先,使用“ xsi:type”有什么好处。我发现这个link非常有用,可以帮助我解决问题。

因此,我们在XML中使用xsi:type来引用驱动类型,例如:

 <X xsi:type="X1">

意味着X和X1是彼此驱动的类型,所以我通过使用继承来修复反序列化,方法是为子类型创建一个新类并使其从父类继承,我们还需要创建一个列表:

    [XmlRoot(ElementName = "X1")]
    public class X1: X
    {
    }

    [XmlRoot(ElementName = "X1List")]
    public class X1List
    {
        [XmlElement(ElementName = "X1")]
        public X1 X1{ get; set; }
    }

在已经使用X的另一个类中,还添加X1,如下所示:

[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; }
}

这应该可以解决反序列化。

对于原始类型,这将是一个棘手的问题,但是您可以使用具有约束的泛型来实现相同的解决方案。