在C#中使用属性控制 XML 序列化来解析XML

fmms 12年前
     <p>今天需要解析一个XML,这个XML和一般情况用.NET的序列化出来的格式不太一样。</p>    <p>我就又补习了一下。</p>    <p>分享一下学习成果吧。</p>    <p>示例代码下载:</p>    <p>http://download.csdn.net/detail/bdstjk/4028340</p>    <p>使用属性可以控制对象的 XML 序列化。</p>    <p>默认情况下,XML 元素名称由类或成员名称确定。在名为 <code>Book</code> 的简单类中,字段 <code>ISBN</code> 将生成 XML 元素标记 <ISBN>,如下面的示例所示。</p>    <pre class="brush:c#; toolbar: true; auto-links: false;">public class Book {     public string ISBN; } // When an instance of the Book class is serialized, it might  // produce this XML: // <ISBN>1234567890</ISBN>.</pre>    <p><br /> 若要重新命名元素,可以更改这种默认行为。下面的代码演示属性 (Attribute) 如何通过设置 XmlElementAttribute 的 ElementName 属性 (Property) 实现此目的。</p>    <pre class="brush:c#; toolbar: true; auto-links: false;">public class TaxRates{     [XmlElement(ElementName = "TaxRate")]     public decimal ReturnTaxRate; }</pre>    <p> </p>    <p>XmlArrayAttribute 和 XmlArrayItemAttribute 属性旨在用于控制数组的序列化。使用这些属性可以控制元素名称、命名空间以及 XML 架构 (XSD) 数据类型(在万维网联合会 [www.w3.org] 文档“XML 架构第 2 部分:数据类型”中进行了定义)。此外,还可以指定数组所能包含的类型。</p>    <p>对于序列化数组时生成的封闭 XML 元素,其属性将由 <strong>XmlArrayAttribute</strong> 确定。例如,默认情况下,序列化下面的数组时,将会生成名为<code>Employees</code> 的 XML 元素。<code>Employees</code> 元素将包含在数组类型<code>Employee</code> 之后命名的一系列元素。</p>    <pre class="brush:c#; toolbar: true; auto-links: false;">public class Group{     public Employee[] Employees; } public class Employee{     public string Name; }</pre>    <p><br /> 序列化实例可能如下所示。</p>    <pre class="brush:xml; toolbar: true; auto-links: false;"><Group> <Employees>     <Employee>         <Name>Haley</Name>     </Employee> </Employees > </Group></pre>    <p> </p>    <p>通过应用 <strong>XmlArrayAttribute</strong>,可以按照以下方式更改 XML 元素的名称。</p>    <pre class="brush:c#; toolbar: true; auto-links: false;">public class Group{     [XmlArray("TeamMembers")]     public Employee[] Employees; }</pre>    <p> </p>    <p>生成的 XML 可能如下所示。</p>    <pre class="brush:xml; toolbar: true; auto-links: false;"><Group> <TeamMembers>     <Employee>         <Name>Haley</Name>     </Employee> </TeamMembers></pre>    <p> </p>    <p>另一方面,<strong>XmlArrayItemAttribute</strong> 可以控制如何序列化数组中包含的项。请注意,该属性将应用于返回数组的字段。</p>    <pre class="brush:c#; toolbar: true; auto-links: false;">public class Group{     [XmlArrayItem("MemberName")]     public Employee[] Employees; }</pre>    <p> </p>    <p>生成的 XML 可能如下所示。</p>    <pre class="brush:xml; toolbar: true; auto-links: false;"><Group> <Employees>     <MemberName>Haley</MemberName> </Employees> </Group></pre>    <p><br />  </p>    <h2 class="heading">序列化派生类</h2>    <div id="sectionSection2" class="seeAlsoNoToggleSection">     <p><strong>XmlArrayItemAttribute</strong> 的另一种用法是,允许序列化派生类。例如,可将派生自 <code>Employee</code> 的另一个名为<code>Manager</code> 的类添加至上一示例中。如果没有应用<strong>XmlArrayItemAttribute</strong>,代码将在运行时失败,原因是无法识别派生类类型。若要解决这个问题,每次为每个可接受类型(基类和派生类)设置 Type 属性 (Property) 时,需要应用该属性 (Attribute) 两次。</p>    </div>    <pre class="brush:c#; toolbar: true; auto-links: false;">public class Group{     [XmlArrayItem(Type = typeof(Employee)),     XmlArrayItem(Type = typeof(Manager))]     public Employee[] Employees; } public class Employee{     public string Name; } public class Manager:Employee{     public int Level; }</pre>    <p><br />  </p>    <p>序列化实例可能如下所示。</p>    <pre class="brush:xml; toolbar: true; auto-links: false;"><Group> <Employees>     <Employee>         <Name>Haley</Name>     </Employee>     <Employee xsi:type = "Manager">         <Name>Ann</Name>         <Level>3</Level>     <Employee> </Employees > </Group></pre>    <h2 class="heading">将数组作为元素序列进行序列化</h2>    <div id="sectionSection3" class="seeAlsoNoToggleSection">     <p>通过将 <strong>XmlElementAttribute</strong> 应用于返回数组的字段,还可以将该数组作为 XML 元素的平面序列进行序列化,如下所示。</p>    </div>    <pre class="brush:c#; toolbar: true; auto-links: false;">public class Group{     [XmlElement]     public Employee[] Employees; }</pre>    <p><br />  </p>    <p>序列化实例可能如下所示。</p>    <pre class="brush:xml; toolbar: true; auto-links: false;"><Group> <Employees>     <Name>Haley</Name> </Employees> <Employees>     <Name>Noriko</Name> </Employees> <Employees>     <Name>Marco</Name> </Employees> </Group></pre>    <p><br />  </p>    <p>区别两种 XML 流的另一个方法是,使用 XML 架构定义工具,从编译好的代码生成 XML 架构 (XSD) 文档文件。没有将属性应用于字段时,架构会以下列方式描述元素。</p>    <div class="code">     <table class="ke-zeroborder" cellspacing="0" cellpadding="0" width="100%">      <tbody>       <tr>        <th> </th>        <th><br /> </th>       </tr>       <tr>        <td colspan="2"><pre><xs:element minOccurs="0" maxOccurs ="1" name="Employees" type="ArrayOfEmployee" /></pre></td>       </tr>      </tbody>     </table>    </div>    <p>将 <strong>XmlElementAttribute</strong> 应用于字段时,生成的架构会以下列方式描述元素。</p>    <div class="code">     <table class="ke-zeroborder" cellspacing="0" cellpadding="0" width="100%">      <tbody>       <tr>        <th> </th>        <th> </th>       </tr>       <tr>        <td colspan="2"><pre><xs:element minOccurs="0" maxOccurs="unbounded" name="Employees" type="Employee" /> </pre></td>       </tr>      </tbody>     </table>    </div>    <h2 class="heading">序列化 ArrayList</h2>    <p>ArrayList 类可能包含各种不同对象的集合。因此,可以按照使用数组的类似方式使用 <strong>ArrayList</strong>。您可以创建返回单个<strong>ArrayList</strong> 的字段,而不用创建返回类型化对象的数组的字段。但是,与数组相同的是,必须将<strong>ArrayList</strong> 包含的对象的类型告知 XmlSerializer。为此,需要为该字段分配<strong>XmlElementAttribute</strong> 的多个实例,如下面的示例所示。</p>    <pre class="brush:c#; toolbar: true; auto-links: false;">public class Group{     [XmlElement(Type = typeof(Employee)),      XmlElement(Type = typeof(Manager))]     public ArrayList Info; }</pre>    <p><br />  </p>    <h2 class="heading">使用 XmlRootAttribute 和 XmlTypeAttribute 控制类的序列化</h2>    <div id="sectionSection5" class="seeAlsoNoToggleSection">     <p>能且只能应用于一个类的属性有下面两种:XmlRootAttribute 和 XmlTypeAttribute。这两种属性非常相似。<strong>XmlRootAttribute</strong> 只能应用于一个类:序列化时,该类表示 XML 文档的开始和结束元素,也就是根元素。另一方面,<strong>XmlTypeAttribute</strong> 可以应用于任何一个类,包括根类。</p>     <p>例如,在上面的示例中,<code>Group</code> 类就是根类,而其所有的公共字段和属性变成 XML 文档中的 XML 元素。因此,只能有一个根类。通过应用<strong>XmlRootAttribute</strong>,可以控制<strong>XmlSerializer</strong> 所生成的 XML 流。例如,可以更改元素名称和命名空间。</p>     <p>使用 <strong>XmlTypeAttribute</strong> 可以控制所生成 XML 的架构。需要通过 XML Web services 发布架构时,这项功能很有用。下面的示例将<strong>XmlTypeAttribute</strong> 和<strong>XmlRootAttribute</strong> 同时应用于同一个类。</p>    </div>    <pre class="brush:c#; toolbar: true; auto-links: false;">[XmlRoot("NewGroupName")] [XmlType("NewTypeName")] public class Group{     public Employee[] Employees; }</pre>    <p><br />  </p>    <p>如果对该类进行编译,并且使用 XML 架构定义工具生成其架构,可能会找到下面描述 <code>Group</code> 的 XML。</p>    <p> </p>    <table class="ke-zeroborder" cellspacing="0" cellpadding="0" width="100%">     <tbody>      <tr>       <td colspan="2"><pre><xs:element name="NewGroupName" type="NewTypeName"></pre></td>      </tr>     </tbody>    </table>    <p></p>    <p>相比之下,如果是对该类的实例进行序列化,则只能在 XML 文档中找到 <code>NewGroupName</code>。</p>    <table class="ke-zeroborder" cellspacing="0" cellpadding="0" width="100%">     <tbody>      <tr>       <td colspan="2"> <p><NewGroupName> . . .</NewGroupName></p> </td>      </tr>     </tbody>    </table>    <p> </p>    <p> </p>    <p>最后来贴一个自己的XML解析实例</p>    <p>XML结构如下:</p>    <pre class="brush:xml; toolbar: true; auto-links: false;"><?xml version="1.0" encoding="utf-8"?> <Root>     <Person IDCard="610424199902230099" Name="小田雨" MedicalID="体检编号" Sex="男" Age="22" MedicalRecordDate ="2011-01-01"  MedicalReportDate="2011-01-01"   MedicalCount="体检次数"  HospitalID="001" HospitalName="兴隆园医院" >         <Results>             <Result></Result>             <Result></Result>             <Result></Result>         </Results>         <Conclusions>             <Conclusion></Conclusion>             <Conclusion></Conclusion>             <Conclusion></Conclusion>         </Conclusions>         <Suggestions>             <Suggestion></Suggestion>             <Suggestion></Suggestion>             <Suggestion></Suggestion>         </Suggestions>         <Health> 为空(预留)</Health>     </Person>      <MedicalItems>         <MedicalSub  ID ="0001" Name="化学检查"  >             <MedicalType ID ="0001001" Name="血常规" MedicalDoc="体检医师名字" MedicalDate="2011-02-13">                  <Item ID="000100010001" Name="白细胞" Unit="G/L" Parameters="3.7--10.0" >                     <Results>H==高,L=低,N=正常</Results>                     <Value>11.1</Value>                     <Disease></Disease>                     <MedicalBodyPart> </MedicalBodyPart>                     <MedicalImage> </MedicalImage>                     <Conclusion ></Conclusion>                 </Item>                 <Item ID="000100010002" Name="红细胞" Unit="G/L" Parameters="3.7--10.0">                     <Results>H==高,L=低,N=正常</Results>                     <Value>11.1</Value>                     <Disease></Disease>                     <MedicalBodyPart> </MedicalBodyPart>                     <MedicalImage> </MedicalImage>                     <Conclusion ></Conclusion>                 </Item>             </MedicalType>         </MedicalSub>         <MedicalSub  ID ="0002" Name="物理检查"  >             <MedicalType ID ="0002001" Name="B超" MedicalDoc="体检医师名字" MedicalDate="2011-02-13">                 <Item ID="000200010001" Name="胸部B超" Unit=" " Parameters="">                     <Results>A=异常,N=正常</Results>                     <Value></Value>                     <Disease>病种,未见异常</Disease>                     <MedicalBodyPart>检查部位:胸部</MedicalBodyPart>                     <MedicalImage>影像所见</MedicalImage>                     <Conclusion >检查结论</Conclusion>                 </Item>                 <Item ID="000200010002" Name="腹部B超" Unit=" " Parameters="">                     <Results>A=异常,N=正常</Results>                     <Value></Value>                     <Disease>病种,未见异常</Disease>                     <MedicalBodyPart>检查部位:腹部</MedicalBodyPart>                     <MedicalImage>影像所见</MedicalImage>                     <Conclusion >检查结论</Conclusion>                 </Item>             </MedicalType>          </MedicalSub>         <MedicalSub  ID ="0005" Name="五官科"  >             <MedicalType ID ="0005001" Name="眼科" MedicalDoc="体检医师名字" MedicalDate="2011-02-13">                 <Item ID="000500010001" Name="视力/右" Unit=" " Parameters="1.0-1.5">                     <Results>A=异常,N=正常</Results>                     <Value>1.5</Value>                     <Disease>病种,未见异常</Disease>                     <MedicalBodyPart>检查部位</MedicalBodyPart>                     <MedicalImage>影像所见</MedicalImage>                     <Conclusion >检查结论</Conclusion>                 </Item>                 <Item ID="000500010002" Name="矫正视力/右" Unit=" " Parameters="1.0-1.5">                     <Results>A=异常,N=正常</Results>                     <Value>0.8</Value>                     <Disease>病种,未见异常</Disease>                     <MedicalBodyPart>检查部位</MedicalBodyPart>                     <MedicalImage>影像所见</MedicalImage>                     <Conclusion >检查结论</Conclusion>                 </Item>             </MedicalType>          </MedicalSub>     </MedicalItems> </Root></pre>    <p><br /> C#代码如下:</p>    <p>代码有点多</p>    <pre class="brush:c#; toolbar: true; auto-links: false;">using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml; using System.Xml.Serialization;  using System.IO;  namespace 天健接口 {     class Program     {         static void Main(string[] args)         {             Root r = new Root();              r.Person = new Person();             r.Person.IDCard = "22";             r.Person.Results = new List<string>();             r.Person.Results.Add("1");             r.Person.Results.Add("1");             r.Person.Results.Add("1");             r.Person.Suggestions = new List<string>();             r.Person.Suggestions.Add("2");             r.Person.Suggestions.Add("2");             r.Person.Suggestions.Add("2");              r.MedicalItems = new List<MedicalSub>();             MedicalSub ms = new MedicalSub();             ms.ID = "ss";             ms.Name="de";             ms.MedicalType = new MedicalType();             ms.MedicalType.ID = "wa";             ms.MedicalType.Name = "s";             ms.MedicalType.MedicalDoc= "qa";             ms.MedicalType.MedicalDate = "2010-5-5";             ms.MedicalType.Item = new List<Item>();             Item it = new Item();             it.ID = "f";             it.Name = "s";             it.Results = "s";             ms.MedicalType.Item.Add(it);             ms.MedicalType.Item.Add(it);             r.MedicalItems.Add(ms);             r.MedicalItems.Add(ms);              Console.WriteLine("序列化成功……");             Console.WriteLine(XmlSerialize.SerializeXML<Root>(r));                                   }     }      [Serializable]     public class Root     {         //[XmlElement]         public Person Person;          public List<MedicalSub> MedicalItems;     }      [Serializable]     public class Person     {         [XmlAttribute]         public string IDCard;          [XmlAttribute]         public string Name;          [XmlAttribute]         public string MedicalID;          [XmlAttribute]         public string Sex;          [XmlAttribute]         public string Age;          [XmlAttribute]         public string MedicalRecordDate;          [XmlAttribute]         public string MedicalReportDate;          [XmlAttribute]         public string MedicalCount;          [XmlAttribute]         public string HospitalID;          [XmlAttribute]         public string HospitalName;          [XmlArrayItem("Result")]         public List<string> Results;          [XmlArrayItem("Conclusion")]         public List<string> Conclusions;          [XmlArrayItem("Suggestion")]         public List<string> Suggestions;          public String Health;     }      [Serializable]     public class MedicalSub     {         [XmlAttribute]         public string ID;          [XmlAttribute]         public string Name;          public MedicalType MedicalType;      }      [Serializable]     public class MedicalType     {         [XmlAttribute]         public string ID;          [XmlAttribute]         public string Name;          [XmlAttribute]         public string MedicalDoc;          [XmlAttribute]         public string MedicalDate;          [XmlElement]         public List<Item> Item;     }      public class Item     {         [XmlAttribute]         public string ID;          [XmlAttribute]         public string Name;          [XmlAttribute]         public string Unit;          [XmlAttribute]         public string Parameters;           public string Results;          public string Value;          public string Disease;          public string MedicalBodyPart;          public string MedicalImage;          public string Conclusion;       }           public class XmlSerialize     {         /// <summary>         /// 反序列化XML为类实例         /// </summary>         /// <typeparam name="T"></typeparam>         /// <param name="xmlObj"></param>         /// <returns></returns>         public static T DeserializeXML<T>(string xmlObj)         {             XmlSerializer serializer = new XmlSerializer(typeof(T));             using (StringReader reader = new StringReader(xmlObj))             {                 return (T)serializer.Deserialize(reader);             }         }          /// <summary>         /// 序列化类实例为XML         /// </summary>         /// <typeparam name="T"></typeparam>         /// <param name="obj"></param>         /// <returns></returns>         public static string SerializeXML<T>(T obj)         {             using (StringWriter writer = new StringWriter())             {                 new XmlSerializer(obj.GetType()).Serialize((TextWriter)writer, obj);                 return writer.ToString();             }         }     }   }</pre>    <p>来自:http://blog.csdn.net/bdstjk/article/details/7210742</p>