C#xml序列化必填字段

时间:2014-06-16 08:34:00

标签: c# .net xml serialization xml-serialization

我需要将某些字段标记为在XML文件中写入,但没有成功。我有一个具有约30个属性的配置类,这就是为什么我不能包含所有这样的属性

    public string SomeProp
    {
        get { return _someProp; }
        set
        {
            if (_someProp == null)
                throw  new ArgumentNullException("value");
            _someProp = value;
        }
    }

和null是代码中的有效值,但不是来自XML的有效值。我正在尝试使用XmlAttribute,但它不会像我预期的那样影响(反序列化时的IOException)。

例如这段代码:

    [XmlElement(IsNullable = true)]
    public String Name { get; set; }

    [XmlElement(IsNullable = true)]
    public String Description { get; set; }

在缺少NameDescription标签时非常有效。


澄清:

类别:

public class MyClass
{
    [XmlElement(IsNullable = true)]
    public String Name { get; set; }

    [XmlElement(IsNullable = true)]
    public String Description { get; set; } 
}

XML:

<?xml version="1.0"?>
<MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>hello</Name>
</MyClass>

代码:

MyClass deserialize = (MyClass)new XmlSerializer(my.GetType()).Deserialize(new FileStream("result.xml", FileMode.Open));
Console.WriteLine(deserialize.Name);
Console.WriteLine(deserialize.Description);

结果:deserialization is successful, Description is null

预期:exception, Description tag not found.

2 个答案:

答案 0 :(得分:3)

我相信你可以采用两种方法。一种是使用一个使用模式的验证XmlReader,另一种是反序列化后的反射检查。最后一个选项是我在这里提供的解决方案:

这个帮助器获取一个流并将给定泛型类型的反序列化为该类型的实例。一旦该对象存在,就可以迭代并检查属性是否使用XmlElementAttribute进行修饰。如果找到该属性,则检查其IsNullable属性,如果为false且对象实例上的属性为false,则抛出异常。

public T ValidatingDeserializer<T>(Stream s)
{
    T deserialize = (T)new XmlSerializer( typeof(T)).Deserialize(s);

    foreach(var pi in typeof(T).GetProperties())
    {
        var xmlnull = pi.GetCustomAttribute(typeof(XmlElementAttribute));
        if (xmlnull!=null)
        {   var xmlnullInst = (XmlElementAttribute) xmlnull;
            if (!xmlnullInst.IsNullable && pi.GetValue(deserialize)==null)
            {
                throw new Exception(String.Format("{0} is null", pi.Name));
            }
        }
    }
    return deserialize;
}

用法

MyClass deserialize = ValidatingDeserializer<MyClass>(
     new FileStream("result.xml", FileMode.Open));

Console.WriteLine(deserialize.Name);
Console.WriteLine(deserialize.Description);

替代基于架构的验证

通过使用架构,您可以针对给定架构verify if the supplied XML document is valid

ReaderFactory

这需要一个xml流和一个模式流,钩住一个引发错误的事件,并返回一个XmlReader,它将是Deserialize方法的输入。

public XmlReader ReaderFactory(Stream xml, Stream schema)
{
    XmlSchemaSet sc = new XmlSchemaSet();

    // Add the schema to the collection.
    sc.Add(null, XmlReader.Create(schema));

    // Set the validation settings.
    XmlReaderSettings settings = new XmlReaderSettings();
    settings.ValidationType = ValidationType.Schema;
    settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;

    settings.Schemas = sc;
    settings.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);

    return XmlReader.Create(xml, settings);
}

ValidateEvent目标

 private static void ValidationCallBack(object sender, ValidationEventArgs e) {
    Console.WriteLine(
        "Validation Error: {0} near line: {1}, pos: {2}", 
        e.Message, 
        e.Exception.LineNumber, 
        e.Exception.LinePosition);
    throw new Exception("illegal xml content");
  }

使用问题中显示的xml的示例模式

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns=""
            elementFormDefault="qualified">

    <xsd:element name="MyClass" >
        <xsd:complexType>
            <xsd:sequence maxOccurs="1">
                <xsd:element name="Name" type="xsd:string"/>
                <xsd:element name="Description" type="xsd:string" minOccurs="1">
                </xsd:element>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>

</xsd:schema>

答案 1 :(得分:3)

你必须使用XmlSerializer吗? DataContractSerializer提供以下选项:

[DataMember(IsRequired = true)]