将XML字符串转换为对象

225

我通过套接字接收XML字符串,并希望将其转换为C#对象。

这些消息的格式为:

<msg>
   <id>1</id>
   <action>stop</action>
</msg>

这怎么做呢?


3
你有这些对象吗,它们已经存在,还是你想要动态生成这些对象? - Stephan
请查看此帖子:https://dev59.com/FXRA5IYBdhLWcg3w9y10 - Aykut Çevik
对我来说,这是最好的选择:https://dev59.com/5XA75IYBdhLWcg3wo6rx#24184283 - Ivan Lopez
15个回答

309

您需要使用安装在Windows SDK中的xsd.exe工具,该工具安装在类似以下目录的目录中:

C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin

在64位计算机上:

C:\Program Files (x86)\Microsoft SDKs\Windows\v6.0A\bin

在 Windows 10 计算机上:

C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin

第一次运行时,您使用 xsd.exe 将示例 XML 转换为 XSD 文件(XML 模式文件):

xsd yourfile.xml

这会给你yourfile.xsd文件,在第二步中,你可以再次使用xsd.exe将其转换为C#类:

xsd yourfile.xsd /c

这将为您提供一个名为yourfile.cs的文件,其中包含一个C#类,您可以使用它来反序列化您获取的XML文件 - 类似于:

XmlSerializer serializer = new XmlSerializer(typeof(msg));
msg resultingMessage = (msg)serializer.Deserialize(new XmlTextReader("yourfile.xml"));

对于大多数情况,应该能够很好地工作。

更新:XML序列化器将使用任何流作为其输入 - 无论是文件还是内存流都可以:

XmlSerializer serializer = new XmlSerializer(typeof(msg));
MemoryStream memStream = new MemoryStream(Encoding.UTF8.GetBytes(inputString));
msg resultingMessage = (msg)serializer.Deserialize(memStream);
或者使用StringReader:
XmlSerializer serializer = new XmlSerializer(typeof(msg));
StringReader rdr = new StringReader(inputString);
msg resultingMessage = (msg)serializer.Deserialize(rdr);

5
您可以打开一个StringReader并传递给Deserialize方法。StringReader派生自TextReader。 - Skurmedel
2
@Steve: 是的,我会的 - 将其反序列化为一个对象,并能够探索对象的属性似乎比对 XML 元素、属性、子节点等进行大量操作更容易。如果 XML 是不规则的并且随时更改或无法预先知道,则 Linq-to-XML 很棒。 - marc_s
这很好!只有一个问题困扰着我: 我拥有的XML如下: '<Request_Group attribute1="value"> <Key name="name" value="value"/> <Request_Data> <Application attribute11="value"> </Application> </Request_Data> </Request_Group>' 由于“Request_Data”标签没有任何属性,因此代码输出为: '[XmlArrayItemAttribute("Application", typeof(REQUEST_GROUPREQUEST_DATAApplication), Form=XmlSchemaForm.Unqualified)] public REQUEST_GROUPREQUEST_DATAApplication[][] REQUEST_DATA { get; set; }' 但是XMLSerializer似乎不喜欢这个二维数组。 - Vinay
9
我认为这个网站比xsd工具要简单得多:http://xmltocsharp.azurewebsites.net/ - nasch
我尝试使用这个xsd工具,但它生成了错误的类。另一个答案中的Paste Special功能可行且更简单。 - Alisson Reinaldo Silva
显示剩余9条评论

272
您有两种选择。
方法1-XSD工具
假设你的XML文件在这个位置 C:\path\to\xml\file.xml
1.打开Developer命令提示符 您可以在 开始菜单>程序>Microsoft Visual Studio 2012>Visual Studio Tools 找到它 或者如果您使用的是Windows 8,只需在“开始屏幕”中开始键入“Developer命令提示符”
2.通过键入 cd /D "C:\path\to\xml" 更改到您的XML文件目录的位置
3.通过键入 xsd file.xml 从XML文件创建XSD文件
4.通过键入 xsd /c file.xsd 创建C#类
完成!您已经从XML文件生成了C#类,位于 C:\path\to\xml\file.cs
方法2-特殊粘贴
需要Visual Studio 2012+和.NET Framework >= 4.5作为项目目标以及安装了“Windows Communication Foundation”单独组件
1.复制您的XML文件内容到剪贴板
2.添加到您的解决方案中一个新的、空的类文件(Shift+Alt+C)
3.打开该文件并在菜单中单击“编辑>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>();

7
干杯。 关于方法2,您需要针对.NET 4.5进行目标设置,否则该选项将不可用。 - timB33
18
第二种方法非常有用!谢谢你教我这个。我之前完全不知道它的存在。 - Dominic Bindley
1
赞成方法2,非常好用。在尝试以编程方式解析XML而不必实现乏味的类时非常棒。 - Alex
1
你应该将“特殊粘贴”作为第一种方法 - 这是最简单的方法。在2017年,“.Net Framework> = 4.5”的限制已经不重要了。 - Michael Freidgeim
2
“Paste XML as classes”需要安装Visual Studio的WCF工作负载。 - Lennart
显示剩余4条评论

57

尝试使用这种方法将Xml转换为对象。它专门用于您正在进行的工作:

protected T FromXml<T>(String xml)
{
    T returnedXmlClass = default(T);

    try
    {
        using (TextReader reader = new StringReader(xml))
        {
            try
            {
                returnedXmlClass = 
                    (T)new XmlSerializer(typeof(T)).Deserialize(reader);
            }
            catch (InvalidOperationException)
            {
                // String passed is not XML, simply return defaultXmlClass
            }
        }
    }
    catch (Exception ex)
    {
    }

    return returnedXmlClass ;        
}

使用以下代码调用:

YourStrongTypedEntity entity = FromXml<YourStrongTypedEntity>(YourMsgString);

7
收到这个错误:xmlns=''未被预期。有什么想法吗? - Prashant
问题在于,你需要提前完美地形成你的类。也许有一个函数,当给定 XML 时输出一个类?xsd.exe 命中率不高(对于复杂的东西大多数情况下都是错过)。 - Yumi Koizumi
1
天啊,我花了好几个小时来处理 .NET 的 XML 序列化器,但这个一开始就能正常工作。 - christopher clark
如果出现“意外错误”,请使用上述解决方案,而不是手动创建类,通过“编辑”->“特殊粘贴”。 - Alex Zel

13

只需以管理员身份运行您的Visual Studio 2013... 复制您的Xml文件内容.. 进入Visual Studio 2013 > 编辑 > 粘贴特殊内容 > 将Xml粘贴为C#类 它将根据您的Xml文件内容创建您的c#类。


11

万一有人觉得这个有用:

public static class XmlConvert
{
    public static string SerializeObject<T>(T dataObject)
    {
        if (dataObject == null)
        {
            return string.Empty;
        }
        try
        {
            using (StringWriter stringWriter = new System.IO.StringWriter())
            {
                var serializer = new XmlSerializer(typeof(T));
                serializer.Serialize(stringWriter, dataObject);
                return stringWriter.ToString();
            }
        }
        catch (Exception ex)
        {
            return string.Empty;
        }
    }

    public static T DeserializeObject<T>(string xml)
         where T : new()
    {
        if (string.IsNullOrEmpty(xml))
        {
            return new T();
        }
        try
        {
            using (var stringReader = new StringReader(xml))
            {
                var serializer = new XmlSerializer(typeof(T));
                return (T)serializer.Deserialize(stringReader);
            }
        }
        catch (Exception ex)
        {
            return new T();
        }
    }
}

您可以通过以下方式调用它:
MyCustomObject myObject = new MyCustomObject();
string xmlString = XmlConvert.SerializeObject(myObject);
myObject = XmlConvert.DeserializeObject<MyCustomObject>(xmlString);

1
XmlConvert.SerializeObject(myObject) 缺少分号 :) - Tim Maes
1
@TimMaes 谢谢!刚刚更新了代码片段!(1975天后);-) - Rasmus-E
再等一天实在是太难熬了 :) - Tim Maes

9
您可以按照上述描述生成类,也可以手动编写它们:
[XmlRoot("msg")]
public class Message
{
    [XmlElement("id")]
    public string Id { get; set; }
    [XmlElement("action")]
    public string Action { get; set; }
}

然后您可以使用 ExtendedXmlSerializer 进行序列化和反序列化。

安装 您可以从nuget安装ExtendedXmlSerializer,或运行以下命令:

Install-Package ExtendedXmlSerializer

序列化:

var serializer = new ConfigurationContainer().Create();
var obj = new Message();
var xml = serializer.Serialize(obj);

反序列化

var obj2 = serializer.Deserialize<Message>(xml);

此序列化程序支持以下功能:
  • 从标准XMLSerializer反序列化XML
  • 序列化类、结构、泛型类、基本类型、泛型列表和字典、数组、枚举
  • 序列化带有属性接口的类
  • 序列化循环引用和引用ID
  • 反序列化旧版本的XML
  • 属性加密
  • 自定义序列化器
  • 支持XmlElementAttribute和XmlRootAttribute
  • POCO - 所有配置(迁移、自定义序列化器......)都在类之外
ExtendedXmlSerializer支持.NET 4.5或更高版本以及.NET Core。您可以将其与WebApi和AspCore集成。

1
很棒的帖子!我根据文档https://github.com/wojtpl2/ExtendedXmlSerializer更新了代码,使之现代化。 - user1477388

3

对于 Damian 给出的优秀回答,简而言之:

public static T ParseXml<T>(this string value) where T : class
{
    var xmlSerializer = new XmlSerializer(typeof(T));
    using (var textReader = new StringReader(value))
    {
        return (T) xmlSerializer.Deserialize(textReader);
    }
}

3

3

我已经查看了所有截止至2020年7月24日的答案,必须有一种更简单、更熟悉的方法来解决这个问题,以下是该方法:

两种情况...第一种是XML字符串格式正确,也就是在遇到根元素之前,它以像<?xml version="1.0" encoding="utf-16"?>或类似的方式开头。问题中的根元素是<msg>。另一种情况是格式不正确,也就是只有根元素(例如问题中的<msg>)及其子节点。

首先,创建一个简单的类,其中包含与XML根节点的子节点匹配的属性,这些属性名称不区分大小写。因此,对于问题,它可能如下所示...

public class TheModel
{
    public int Id { get; set; }
    public string Action { get; set; }
}

以下是代码的其余部分...
// These are the key using statements to add.
using Newtonsoft.Json;
using System.Xml;

bool isWellFormed = false;
string xml =  = @"
<msg>
   <id>1</id>
   <action>stop</action>
</msg>
";

var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(xml);
if (isWellFormed)
{
    xmlDocument.RemoveChild(xmlDocument.FirstChild); 
    /* i.e. removing the first node, which is the declaration part. 
    Also, if there are other unwanted parts in the XML, 
    write another similar code to locate the nodes 
    and remove them to only leave the desired root node 
    (and its child nodes).*/
}

var serializedXmlNode = JsonConvert.SerializeXmlNode(
            xmlDocument, 
            Newtonsoft.Json.Formatting.Indented, 
            true
            );
var theDesiredObject = JsonConvert.DeserializeObject<TheModel>(serializedXmlNode);

2
我知道这个问题很旧,但我偶然发现它并且我有一个与其他人不同的答案 :-)
通常的方式(如上面的评论者所提到的)是生成一个类并反序列化你的xml。
但是(警告:这里有无耻的自我推销),我刚刚发布了一个nuget包here,你不需要这样做。你只需执行以下操作:
string xml = System.IO.File.ReadAllText(@"C:\test\books.xml");
var book = Dandraka.XmlUtilities.XmlSlurper.ParseText(xml);

那就是它,没有其他需要的东西。而且,最重要的是,如果你的xml发生变化,你的对象也会自动变化。如果您希望直接下载dll,请访问github页面这里

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接