如何将XML文件反序列化成为内存中的一个实体类

来源:互联网 发布:细说php第二版的编辑 编辑:程序博客网 时间:2024/05/17 04:20
首先需要通过xsd文件来验证一下传入的xml文件是否符合相应的格式要求。xsd文件就是用来规定xml文件格式的定义文件。其实就类似于类与实例的关系。一个类规定了实例应该具有的属性,而在runtime中的实例则是类的实例化。xsd文件规定了xml应该具有的属性,xml是xsd的实例化。

现有一个类,如何得到对应的xsd文件?可以通过VS自带的XSD工具实现。具体方法可以参照MSDN。比如说,我们通过class得到的xsd文件如下

<?xml version="1.0" encoding="utf-8"?><xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"           xmlns:tns="http://tempuri.org/PurchaseOrderSchema.xsd"           targetNamespace="http://tempuri.org/PurchaseOrderSchema.xsd"           elementFormDefault="qualified">  <xsd:element name="PurchaseOrder" type="tns:PurchaseOrderType"/>  <xsd:complexType name="PurchaseOrderType">    <xsd:sequence>      <xsd:element name="ShipTo" type="tns:USAddress" maxOccurs="2"/>      <xsd:element name="BillTo" type="tns:USAddress"/>    </xsd:sequence>    <xsd:attribute name="OrderDate" type="xsd:date"/>  </xsd:complexType>  <xsd:complexType name="USAddress">    <xsd:sequence>      <xsd:element name="name"   type="xsd:string"/>      <xsd:element name="street" type="xsd:string"/>      <xsd:element name="city"   type="xsd:string"/>      <xsd:element name="state"  type="xsd:string"/>      <xsd:element name="zip"    type="xsd:integer"/>    </xsd:sequence>    <xsd:attribute name="country" type="xsd:NMTOKEN" fixed="US"/>  </xsd:complexType></xsd:schema>

当我们从Message Queue或者其他的什么服务器或者地方获取到XML文件后,我们如何进行向内存中实体类的转化呢?XML文件如下

<?xml version="1.0" encoding="utf-8"?><PurchaseOrder OrderDate="1900-01-01" xmlns="http://tempuri.org/PurchaseOrderSchema.xsd">  <ShipTo country="US">    <name>name1</name>    <street>street1</street>    <city>city1</city>    <state>state1</state>    <zip>1</zip>  </ShipTo>  <ShipTo country="US">    <name>name2</name>    <street>street2</street>    <city>city2</city>    <state>state2</state>    <zip>-79228162514264337593543950335</zip>  </ShipTo>  <BillTo country="US">    <name>name1</name>    <street>street1</street>    <city>city1</city>    <state>state1</state>    <zip>1</zip>  </BillTo></PurchaseOrder>
这里总结了一个工具类,可以供大家参考

     public class XmlValidator     {        private readonly XmlSchemaSet _schemaSet;        //在使用的时候,需要把xsd作为嵌入式资源放入到dll中,在构造方法中需要传入要验证的xml对应的xsd文件的名称            public XmlValidator(IEnumerable<string> schemaResourcePaths)        {    //XmlSchemaSet是一系列xsd的集合,只要xml满足其中一个xsd,就算符合要求。因为在项目中,有时候传过来的是多种            //类对应的xsd,需要反序列化成不止一种的实例,所以在Validate的时候,有多个xsd            _schemaSet = new XmlSchemaSet();            _schemaSet.ValidationEventHandler += SchemaValidationErrorHandler;                        //从dll中获取相应的xsd的内容            Assembly resourceAssembly = Assembly.GetCallingAssembly();            foreach (var schemaResourcePath in schemaResourcePaths)            {                using (var schemaStream = EmbeddedResourceReader.GetStream(schemaResourcePath, resourceAssembly))                {                    AddSchema(schemaStream);                }            }        }        private void AddSchema(Stream schemaStream)        {            using (var reader = new StreamReader(schemaStream))            {                var xmlSchema = XmlSchema.Read(reader, SchemaValidationErrorHandler);                _schemaSet.Add(xmlSchema);            }        }                //这个是在xml文件不符合要求的时候,会触发这个方法        private static void SchemaValidationErrorHandler(object sender, ValidationEventArgs e)        {            throw new Exception(e.Message);        }        public void Validate(string message)        {            //XmlReaderSettings是最外部的类,包含SchemaSet, ValidationEventHandler等等            var settings = new XmlReaderSettings {ValidationType = ValidationType.Schema};            settings.Schemas.Add(_schemaSet);            settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;            var errorMessages = new StringBuilder();            var isValid = true;            settings.ValidationEventHandler += (o, args) =>                                                   {                                                       errorMessages.AppendFormat("XML validation error: {0}",                                                                                  args.Message);                                                       errorMessages.AppendLine();                                                       isValid = false;                                                   };            //通过Create, Read方法来开始验证            using (var reader = XmlReader.Create(new StringReader(message), settings))            {                try                {                    while (reader.Read())                    {                    }                }                catch(XmlException e)                {                    throw new Exception("Message is not valid XML", e);                }            }            if (!isValid)                throw new Exception("Message is not valid towards any of the given schemas." + errorMessages.ToString());        }    }
如何验证无误了,通过下边的代码就可以完成向类的实例的转换
    public class GenericXmlSerializer<TProxy>    {        // ReSharper disable StaticFieldInGenericType        private static readonly XmlSerializer Serializer = new XmlSerializer(typeof(TProxy));        // ReSharper restore StaticFieldInGenericType        public static string ToXml(TProxy proxy)        {            var sb = new StringBuilder();            var sw = new StringWriter(sb);            Serializer.Serialize(sw, proxy);            return sb.ToString();        }        public static TProxy FromXml(string xml)        {            return (TProxy)Serializer.Deserialize(new XmlTextReader(new StringReader(xml)));        }    }

下边的代码就是条用上边的这两个工具方法

public void Deserialize(string xml){     XmlValidator validator = new XmlValidator(new List<string>(){"Customer.xsd"});     validator.Validate();     GenericXmlSerializer<Customer> gs = new GenericXmlSerializer<Customer>();     Customer customer = gs.FromXml(xml);}

到这里,我们就把一个XML文件转换成内存中的Customer实例对象了。

0 0