C# 如何反序列化 XML 文档

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/364253/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 00:39:33  来源:igfitidea点击:

How to Deserialize XML document

c#asp.netxmlserializationxml-deserialization

提问by Alex

How do I Deserialize this XML document:

我如何反序列化这个 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>

I have this:

我有这个:

[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;
    }
}

that don't seem to work :-(

这似乎不起作用:-(

采纳答案by Kevin Tighe

Here's a working version. I changed the XmlElementAttributelabels to XmlElementbecause in the xml the StockNumber, Make and Model values are elements, not attributes. Also I removed the reader.ReadToEnd();(that functionreads the whole stream and returns a string, so the Deserialize()function couldn't use the reader anymore...the position was at the end of the stream). I also took a few liberties with the naming :).

这是一个工作版本。我将XmlElementAttribute标签更改为XmlElement因为在 xml 中 StockNumber、Make 和 Model 值是元素,而不是属性。我还删除了reader.ReadToEnd();(该函数读取整个流并返回一个字符串,因此该Deserialize()函数无法再使用读取器......位置在流的末尾)。我还对命名采取了一些自由:)。

Here are the classes:

以下是课程:

[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; }
}

The Deserialize function:

反序列化功能:

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();

And the slightly tweaked xml (I needed to add a new element to wrap <Cars>...Net is picky about deserializing arrays):

和稍微调整的 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>

回答by Joel Coehoorn

See if this helps:

看看这是否有帮助:

[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; }
}

And failing that use the xsd.exe program that comes with visual studio to create a schema document based on that xml file, and then use it again to create a class based on the schema document.

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

回答by Marc Gravell

How about you just save the xml to a file, and use xsdto generate C# classes?

将xml 保存到文件中,然后使用xsd生成C# 类如何?

  1. Write the file to disk (I named it foo.xml)
  2. Generate the xsd: xsd foo.xml
  3. Generate the C#: xsd foo.xsd /classes
  1. 将文件写入磁盘(我将其命名为 foo.xml)
  2. 生成 xsd: xsd foo.xml
  3. 生成 C#: xsd foo.xsd /classes

Et voila - and C# code file that should be able to read the data via XmlSerializer:

Et voila - 和 C# 代码文件应该能够通过XmlSerializer以下方式读取数据:

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

(include the generated foo.cs in the project)

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

回答by Marc Gravell

The following snippet should do the trick (and you can ignore most of the serialization attributes):

以下代码段应该可以解决问题(您可以忽略大多数序列化属性):

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);
}

回答by janbak

I don't think .net is 'picky about deserializing arrays'. The first xml document is not well formed. There is no root element, although it looks like there is. The canonical xml document has a root and at least 1 element (if at all). In your example:

我不认为 .net '对反序列化数组很挑剔'。第一个 xml 文档格式不正确。没有根元素,虽然看起来有。规范的 xml 文档有一个根和至少 1 个元素(如果有的话)。在你的例子中:

<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>

回答by sheetal nainwal

try this block of code if your .xml file has been generated somewhere in disk and if you have used List<T>:

如果您的 .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();`

Note: C:\serialize.xmlis my .xml file's path. You can change it for your needs.

注意:C:\serialize.xml是我的 .xml 文件的路径。您可以根据需要更改它。

回答by Damian Drygiel

You have two possibilities.

你有两种可能性。

Method 1. XSDtool

方法一、XSD工具



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

  1. Open Developer Command Prompt
    You can find it in Start Menu > Programs > Microsoft Visual Studio 2012 > Visual Studio ToolsOr if you have Windows 8 can just start typing Developer Command Promptin Start screen
  2. Change location to your XML file directory by typing cd /D "C:\path\to\xml"
  3. Create XSD filefrom your xml file by typing xsd file.xml
  4. Create C# classesby typing xsd /c file.xsd
  1. 打开开发人员命令提示符
    您可以在Start Menu > Programs > Microsoft Visual Studio 2012 > Visual Studio Tools或者如果您有 Windows 8 可以在开始屏幕中开始键入开发人员命令提示符
  2. 通过键入将位置更改为您的 XML 文件目录 cd /D "C:\path\to\xml"
  3. 通过键入从您的 xml 文件创建XSD 文件xsd file.xml
  4. 通过键入创建C# 类xsd /c file.xsd

And that's it! You have generated C# classes from xml file in C:\path\to\xml\file.cs

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

Method 2 - Paste special

方法 2 - 特殊粘贴



所需的 Visual Studio 2012+

  1. Copy content of your XML file to clipboard
  2. Add to your solution new, empty class file (Shift+Alt+C)
  3. Open that file and in menu click Edit > Paste special > Paste XML As Classes
    enter image description here
  1. 将 XML 文件的内容复制到剪贴板
  2. 添加到您的解决方案新的,空的类文件(Shift+ Alt+ C
  3. 打开该文件并在菜单中单击 Edit > Paste special > Paste XML As Classes
    在此处输入图片说明

And that's it!

就是这样!

Usage

用法



Usage is very simple with this helper class:

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

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());
        }
    }
}

All you have to do now, is:

你现在要做的就是:

    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>();

回答by goku_da_master

If you're getting errors using xsd.exe to create your xsd file, then use the XmlSchemaInference class as mentioned on msdn. Here's a unit test to demonstrate:

如果您在使用 xsd.exe 创建 xsd 文件时遇到错误,请使用msdn 上提到的 XmlSchemaInference 类。这是一个单元测试来演示:

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

回答by XU Weijiang

You can just change one attribute for you Cars car property from XmlArrayItem to XmlElment. That is, from

您只需将 Cars 汽车属性的一个属性从 XmlArrayItem 更改为 XmlElment。也就是说,从

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

to

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

回答by makdu

The idea is to have all level being handled for deserialization Please see a sample solution that solved my similar issue

这个想法是处理所有级别以进行反序列化请查看解决我类似问题的示例解决方案

<?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> 

The above XML is handled in two level

上面的 XML 分两级处理

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

}

The Inner level

内在层次

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; }

}

Same Way you need multiple level with car as arrayCheck this example for multilevel deserialization

同样的方式你需要多级car as array检查这个例子进行多级反序列化