在C#中使用xsi:nil =“true”反序列化XML元素

时间:2016-06-24 16:47:25

标签: c# .net xml deserialization xmlserializer

我正在尝试使用C#中的XmlSerializer反序列化XML文件。

使用xsd实用程序自动生成后面的目标类。

    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
    [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = true)]
    public partial class location
    {

        private string cityField;

        private string countryField;

        private string stateField;

        private string textField;

        /// <remarks/>
        [System.Xml.Serialization.XmlAttributeAttribute()]
        public string city
        {
            get
            {
                return this.cityField;
            }
            set
            {
                this.cityField = value;
            }
        }

        /// <remarks/>
        [System.Xml.Serialization.XmlAttributeAttribute()]
        public string country
        {
            get
            {
                return this.countryField;
            }
            set
            {
                this.countryField = value;
            }
        }

        /// <remarks/>
        [System.Xml.Serialization.XmlAttributeAttribute()]
        public string state
        {
            get
            {
                return this.stateField;
            }
            set
            {
                this.stateField = value;
            }
        }

        /// <remarks/>
        [System.Xml.Serialization.XmlTextAttribute()]
        public string Text
        {
            get
            {
                return this.textField;
            }
            set
            {
                this.textField = value;
            }
        }
    }

一切正常,直到我到达文件的这一部分:

<locations>
    <location country="PARAGUAY" city="Ciudad del Este" state="Alto Parana" xsi:nil="true"/>
    <location country="BRAZIL" city="Passo Fundo" state="Rio Grande do Sul" xsi:nil="true"/>
</locations>

作为stated in the MSDN,具有xsi:nil =“true”的元素将被反序列化为空对象,完全失去所有属性。在C#中,这将转换为空对象。

有没有办法改变这种行为,以便反序列化三个属性?

提前感谢任何建议!

编辑1:

这是关联的命名空间:

<records xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="structure.xsd">
    (location is within here somewhere)
</records>

2 个答案:

答案 0 :(得分:4)

如果您只想放弃xsi:nil属性,请在引用[XmlElement]的包含类中的属性的location属性中设置XmlElementAttribute.IsNullable = false。 例如。如果你有

[System.Xml.Serialization.XmlRootAttribute("locations", Namespace = "")]
public class LocationList
{
    [XmlElement("location", IsNullable = true)]
    public List<location> Locations { get; set; }
}

手动将其更改为:

[System.Xml.Serialization.XmlRootAttribute("locations", Namespace = "")]
public class LocationList
{
    [XmlElement("location", IsNullable = false)]
    public List<location> Locations { get; set; }
}

如果您希望绑定同时绑定到xsi:nil,同时绑定到其他属性值,除了设置IsNullable = false之外,您还可以添加手动属性Can I have null attribute and other attribute at the same tag in XML created by XSD C# generated class?中显示的那一行:

public partial class location
{
    bool nil;

    [XmlAttribute("nil", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
    public bool Nil
    {
        get
        {
            return nil;
        }
        set
        {
            nil = value;
        }
    }

    public bool ShouldSerializeNil() { return nil == true; }
}

示例fiddle

您还可以预处理和后处理XML以重命名xsi:nil属性,如this answer中所述。

答案 1 :(得分:2)

尝试使用自定义XmlReader。当不可能更改用于反序列化的类时,此方法可能很有用。此外,它不需要额外的内存消耗。

public class NilIgnoreReader : XmlTextReader
{
    public NilIgnoreReader(string url) : base(url) { }

    bool isLocation = false;

    public override bool Read()
    {
        bool read = base.Read();

        if (NodeType == XmlNodeType.Element && LocalName == "location")
            isLocation = true;

        return read;
    }

    public override string GetAttribute(string localName, string namespaceURI)
    {
        if (isLocation && localName == "nil" &&
            namespaceURI == "http://www.w3.org/2001/XMLSchema-instance")
        {
            isLocation = false;
            return "false";
        }
        return base.GetAttribute(localName, namespaceURI);
    }
}

NilIgnoreReader元素绑定到false命名空间的nil属性的http://www.w3.org/2001/XMLSchema-instance返回location

用法

var xs = new XmlSerializer(typeof(Records));
Records record;

using (var reader = new NilIgnoreReader("test.xml"))
    record = (Records)xs.Deserialize(reader);

它适用于XML,如

<?xml version="1.0"?>
<records xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="structure.xsd">
  <locations>
    <location country="PARAGUAY" city="Ciudad del Este" state="Alto Parana" xsi:nil="true"/>
    <location country="BRAZIL" city="Passo Fundo" state="Rio Grande do Sul" xsi:nil="true"/>
  </locations>
</records>

和类似

的类
[XmlRoot("records")]
public class Records
{
    [XmlArray("locations")]
    [XmlArrayItem("location")]
    public Location[] Locations { get; set; }
}

public class Location
{
    [XmlAttribute("country")]
    public string Country { get; set; }
    [XmlAttribute("city")]
    public string City { get; set; }
    [XmlAttribute("state")]
    public string State { get; set; }
}