如何反序列化XML文档

如何反序列化这个XML文档:

<?xml version="1.0" encoding="utf-8"?> <Cars> <Car> <StockNumber>1020</StockNumber> <Make>Nissan</Make> <Model>Sentra</Model> </Car> <Car> <StockNumber>1010</StockNumber> <Make>Toyota</Make> <Model>Corolla</Model> </Car> <Car> <StockNumber>1111</StockNumber> <Make>Honda</Make> <Model>Accord</Model> </Car> </Cars> 

我有这个:

 [Serializable()] public class Car { [System.Xml.Serialization.XmlElementAttribute("StockNumber")] public string StockNumber{ get; set; } [System.Xml.Serialization.XmlElementAttribute("Make")] public string Make{ get; set; } [System.Xml.Serialization.XmlElementAttribute("Model")] public string Model{ get; set; } } 

 [System.Xml.Serialization.XmlRootAttribute("Cars", Namespace = "", IsNullable = false)] public class Cars { [XmlArrayItem(typeof(Car))] public Car[] Car { get; set; } } 

 public class CarSerializer { public Cars Deserialize() { Cars[] cars = null; string path = HttpContext.Current.ApplicationInstance.Server.MapPath("~/App_Data/") + "cars.xml"; XmlSerializer serializer = new XmlSerializer(typeof(Cars[])); StreamReader reader = new StreamReader(path); reader.ReadToEnd(); cars = (Cars[])serializer.Deserialize(reader); reader.Close(); return cars; } } 

那似乎不起作用:-(

这是一个工作版本。 我将XmlElementAttribute标签更改为XmlElement,因为在xml中,StockNumber,Make和Model值是元素,而不是属性。 我也删除了reader.ReadToEnd(); (该函数读取整个stream并返回一个string,所以Deserialze()函数不能再使用阅读器…位置在stream的末尾)。 我也采取了一些自由与命名:)。

这里是类:

 [Serializable()] public class Car { [System.Xml.Serialization.XmlElement("StockNumber")] public string StockNumber { get; set; } [System.Xml.Serialization.XmlElement("Make")] public string Make { get; set; } [System.Xml.Serialization.XmlElement("Model")] public string Model { get; set; } } [Serializable()] [System.Xml.Serialization.XmlRoot("CarCollection")] public class CarCollection { [XmlArray("Cars")] [XmlArrayItem("Car", typeof(Car))] public Car[] Car { get; set; } } 

反序列化函数:

 CarCollection cars = null; string path = "cars.xml"; XmlSerializer serializer = new XmlSerializer(typeof(CarCollection)); StreamReader reader = new StreamReader(path); cars = (CarCollection)serializer.Deserialize(reader); reader.Close(); 

稍微调整xml(我需要添加一个新元素来包装<Cars> … Net对挑选数组进行挑剔):

 <?xml version="1.0" encoding="utf-8"?> <CarCollection> <Cars> <Car> <StockNumber>1020</StockNumber> <Make>Nissan</Make> <Model>Sentra</Model> </Car> <Car> <StockNumber>1010</StockNumber> <Make>Toyota</Make> <Model>Corolla</Model> </Car> <Car> <StockNumber>1111</StockNumber> <Make>Honda</Make> <Model>Accord</Model> </Car> </Cars> </CarCollection> 

你如何保存XML到一个文件,并使用XSD ?

  1. 将文件写入磁盘(我将其命名为foo.xml)
  2. 生成xsd: xsd foo.xml
  3. 生成C#: xsd foo.xsd /classes

Et瞧 – 和应该能够通过XmlSerializer读取数据的C#代码文件:

  XmlSerializer ser = new XmlSerializer(typeof(Cars)); Cars cars; using (XmlReader reader = XmlReader.Create(path)) { cars = (Cars) ser.Deserialize(reader); } 

(在项目中包含生成的foo.cs)

你有两种可能性。

方法1. XSD工具


假设您的XML文件位于C:\path\to\xml\file.xml

  1. 打开开发人员命令提示符
    您可以在Start Menu > Programs > Microsoft Visual Studio 2012 > Visual Studio Toolsfind它或者如果您有Windows 8,只需在开始屏幕中inputDeveloper Command Prompt
  2. 通过inputcd /D "C:\path\to\xml"位置更改为XML文件目录
  3. 通过键入xsd file.xml从xml文件创buildXSD文件
  4. 通过键入xsd /c file.xsd创buildC#类

而就是这样! 您已经从C:\path\to\xml\file.cs xml文件生成了C#类C:\path\to\xml\file.cs

方法2 – 特殊粘贴


必需的Visual Studio 2012+

  1. 将XML文件的内容复制到剪贴板
  2. 添加到您的解决scheme新的空的类文件( Shift + Alt + C
  3. 打开该文件,然后在菜单中单击Edit > Paste special > Paste XML As Classes
    在这里输入图像描述

而就是这样!

用法


这个辅助类的用法非常简单:

 using System; using System.IO; using System.Web.Script.Serialization; // Add reference: System.Web.Extensions using System.Xml; using System.Xml.Serialization; namespace Helpers { internal static class ParseHelpers { private static JavaScriptSerializer json; private static JavaScriptSerializer JSON { get { return json ?? (json = new JavaScriptSerializer()); } } public static Stream ToStream(this string @this) { var stream = new MemoryStream(); var writer = new StreamWriter(stream); writer.Write(@this); writer.Flush(); stream.Position = 0; return stream; } public static T ParseXML<T>(this string @this) where T : class { var reader = XmlReader.Create(@this.Trim().ToStream(), new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Document }); return new XmlSerializer(typeof(T)).Deserialize(reader) as T; } public static T ParseJSON<T>(this string @this) where T : class { return JSON.Deserialize<T>(@this.Trim()); } } } 

你现在要做的就是:

  public class JSONRoot { public catalog catalog { get; set; } } // ... string xml = File.ReadAllText(@"D:\file.xml"); var catalog1 = xml.ParseXML<catalog>(); string json = File.ReadAllText(@"D:\file.json"); var catalog2 = json.ParseJSON<JSONRoot>(); 

下面的代码片段应该能够做到这一点(你可以忽略大部分的序列化属性):

 public class Car { public string StockNumber { get; set; } public string Make { get; set; } public string Model { get; set; } } [XmlRootAttribute("Cars")] public class CarCollection { [XmlElement("Car")] public Car[] Cars { get; set; } } 

 using (TextReader reader = new StreamReader(path)) { XmlSerializer serializer = new XmlSerializer(typeof(CarCollection)); return (CarCollection) serializer.Deserialize(reader); } 

看看这是否有帮助:

 [Serializable()] [System.Xml.Serialization.XmlRootAttribute("Cars", Namespace = "", IsNullable = false)] public class Cars { [XmlArrayItem(typeof(Car))] public Car[] Car { get; set; } } 

 [Serializable()] public class Car { [System.Xml.Serialization.XmlElement()] public string StockNumber{ get; set; } [System.Xml.Serialization.XmlElement()] public string Make{ get; set; } [System.Xml.Serialization.XmlElement()] public string Model{ get; set; } } 

如果失败,则使用Visual Studio附带的xsd.exe程序来创build基于该xml文件的模式文档,然后再次使用它来基于模式文档创build类。

我不认为.NET对数组的反序列化是挑剔的。 第一个xml文档结构不正确。 没有根元素,尽pipe它看起来像是存在的。 规范的xml文档有一个根和至less1个元素(如果有的话)。 在你的例子中:

 <Root> <-- well, the root <Cars> <-- an element (not a root), it being an array <Car> <-- an element, it being an array item ... </Car> </Cars> </Root> 

如果你的.xml文件已经在磁盘的某个地方生成了,并且你已经使用了List<T> ,那么试试这段代码:

 //deserialization XmlSerializer xmlser = new XmlSerializer(typeof(List<Item>)); StreamReader srdr = new StreamReader(@"C:\serialize.xml"); List<Item> p = (List<Item>)xmlser.Deserialize(srdr); srdr.Close();` 

注意: C:\serialize.xml是我的.xml文件的path。 您可以根据自己的需求进行更改。

这个想法是所有的级别被处理反序列化请参阅解决我的类似问题的示例解决scheme

 <?xml version="1.0" ?> <TRANSACTION_RESPONSE> <TRANSACTION> <TRANSACTION_ID>25429</TRANSACTION_ID> <MERCHANT_ACC_NO>02700701354375000964</MERCHANT_ACC_NO> <TXN_STATUS>F</TXN_STATUS> <TXN_SIGNATURE>a16af68d4c3e2280e44bd7c2c23f2af6cb1f0e5a28c266ea741608e72b1a5e4224da5b975909cc43c53b6c0f7f1bbf0820269caa3e350dd1812484edc499b279</TXN_SIGNATURE> <TXN_SIGNATURE2>B1684258EA112C8B5BA51F73CDA9864D1BB98E04F5A78B67A3E539BEF96CCF4D16CFF6B9E04818B50E855E0783BB075309D112CA596BDC49F9738C4BF3AA1FB4</TXN_SIGNATURE2> <TRAN_DATE>29-09-2015 07:36:59</TRAN_DATE> <MERCHANT_TRANID>150929093703RUDZMX4</MERCHANT_TRANID> <RESPONSE_CODE>9967</RESPONSE_CODE> <RESPONSE_DESC>Bank rejected transaction!</RESPONSE_DESC> <CUSTOMER_ID>RUDZMX</CUSTOMER_ID> <AUTH_ID /> <AUTH_DATE /> <CAPTURE_DATE /> <SALES_DATE /> <VOID_REV_DATE /> <REFUND_DATE /> <REFUND_AMOUNT>0.00</REFUND_AMOUNT> </TRANSACTION> </TRANSACTION_RESPONSE> 

上面的XML是在两个层次上处理的

  [XmlType("TRANSACTION_RESPONSE")] public class TransactionResponse { [XmlElement("TRANSACTION")] public BankQueryResponse Response { get; set; } } 

内在层面

 public class BankQueryResponse { [XmlElement("TRANSACTION_ID")] public string TransactionId { get; set; } [XmlElement("MERCHANT_ACC_NO")] public string MerchantAccNo { get; set; } [XmlElement("TXN_SIGNATURE")] public string TxnSignature { get; set; } [XmlElement("TRAN_DATE")] public DateTime TranDate { get; set; } [XmlElement("TXN_STATUS")] public string TxnStatus { get; set; } [XmlElement("REFUND_DATE")] public DateTime RefundDate { get; set; } [XmlElement("RESPONSE_CODE")] public string ResponseCode { get; set; } [XmlElement("RESPONSE_DESC")] public string ResponseDesc { get; set; } [XmlAttribute("MERCHANT_TRANID")] public string MerchantTranId { get; set; } } 

相同的方式,你需要多个级别的car as array 检查这个例子的多级反序列化

尝试这个通用类用于Xml序列化和反序列化。

 public class SerializeConfig<T> where T : class { public static void Serialize(string path, T type) { var serializer = new XmlSerializer(type.GetType()); using (var writer = new FileStream(path, FileMode.Create)) { serializer.Serialize(writer, type); } } public static T DeSerialize(string path) { T type; var serializer = new XmlSerializer(typeof(T)); using (var reader = XmlReader.Create(path)) { type = serializer.Deserialize(reader) as T; } return type; } } 

如果使用xsd.exe创buildxsd文件时出现错误,请使用msdn上提到的XmlSchemaInference类。 这是一个unit testing来演示:

 using System.Xml; using System.Xml.Schema; [TestMethod] public void GenerateXsdFromXmlTest() { string folder = @"C:\mydir\mydata\xmlToCSharp"; XmlReader reader = XmlReader.Create(folder + "\some_xml.xml"); XmlSchemaSet schemaSet = new XmlSchemaSet(); XmlSchemaInference schema = new XmlSchemaInference(); schemaSet = schema.InferSchema(reader); foreach (XmlSchema s in schemaSet.Schemas()) { XmlWriter xsdFile = new XmlTextWriter(folder + "\some_xsd.xsd", System.Text.Encoding.UTF8); s.Write(xsdFile); xsdFile.Close(); } } // now from the visual studio command line type: xsd some_xsd.xsd /classes 

您可以为您更改一个属性将汽车属性从XmlArrayItem改为XmlElment。 那就是从

 [System.Xml.Serialization.XmlRootAttribute("Cars", Namespace = "", IsNullable = false)] public class Cars { [XmlArrayItem(typeof(Car))] public Car[] Car { get; set; } } 

 [System.Xml.Serialization.XmlRootAttribute("Cars", Namespace = "", IsNullable = false)] public class Cars { [XmlElement("Car")] public Car[] Car { get; set; } } 

我的解决scheme

  1. 使用“ Edit > Past Special > Paste XML As Classes来获取代码中的类
  2. 尝试类似这样的:创build该类的列表( List<class1 >),然后使用XmlSerializer将该列表序列化为一个xml文件。
  3. 现在,您只需使用您的数据replace该文件的正文,并尝试对其进行deserialize

码:

 StreamReader sr = new StreamReader(@"C:\Users\duongngh\Desktop\Newfolder\abc.txt"); XmlSerializer xml = new XmlSerializer(typeof(Class1[])); var a = xml.Deserialize(sr); sr.Close(); 

注意:您必须注意根名称,不要更改它。 我的是“ArrayOfClass1”