gpt4 book ai didi

c# - 使用 Servicestack.Text 进行 XML 反序列化

转载 作者:太空狗 更新时间:2023-10-29 17:33:18 24 4
gpt4 key购买 nike

我在学习Servicestack.Text库,因为它具有一些最佳功能。我正在尝试将 XML 反序列化为我的 DTO 之一,如下所示;

C# 代码:[此处为控制台应用程序的相关代码]

class Program
{
static void Main(string[] args)
{
string str = "http://static.cricinfo.com/rss/livescores.xml";
WebClient w = new WebClient();
string xml = w.DownloadString(str);
Response rss = xml.FromXml<Response>();
foreach (var item in rss.rss.Channel.item)
{
Console.WriteLine(item.title);
}
Console.Read();
}
}

您可以在 str[在程序中给出] 处浏览 XML 文件。我已经为反序列化准备了 DTO。它们如下:

public  class Response
{
public RSS rss { get; set; }
}

public class RSS
{
public string Version { get; set; }
public ChannelClass Channel { get; set; }
}

public class ChannelClass
{
public string title { get; set; }
public string ttl { get; set; }
public string description { get; set; }
public string link { get; set; }
public string copyright { get; set; }
public string language { get; set; }
public string pubDate { get; set; }
public List<ItemClass> item { get; set; }
}

public class ItemClass
{
public string title { get; set; }
public string link { get; set; }
public string description { get; set; }
public string guid { get; set; }
}

当我运行该程序时,出现如下所示的异常:

enter image description here

因此,为了更改 Elementnamespace,我做了以下解决方法:

我将 DataContractAttribute 放在我的 Response 类中,如下所示:

[DataContract(Namespace = "")]
public class Response
{
public RSS rss { get; set; }
}

我通过在反序列化之前添加以下两行来更改 Element 名称,如下所示

  //To change rss Element to Response as in Exception
xml = xml.Replace("<rss version=\"2.0\">","<Response>");
//For closing tag
xml = xml.Replace("</rss>","</Response>");

但是,由于反序列化的 rss 对象为 null,它在 foreach 循环中给出了另一个异常。那么,我应该如何使用 Servicestack.Text 以正确的方式反序列化它?

注意:

我很清楚如何用其他库反序列化,我只想用 ServiceStack 来做。

最佳答案

TLDR:使用 XmlSerializer 从您无法控制的 xml 方言中反序列化; ServiceStack 专为代码优先开发而设计,不能适用于通用 xml 解析。


ServiceStack.Text 实现自定义 Xml 序列化程序 - 它在后台使用 DataContractSerializerFromXml 只是语法糖。

使用DataContractSerializer解析Xml

如您所见,DataContractSerializer命名空间 很挑剔。一种方法是在类上显式指定命名空间,但如果这样做,则需要在所有地方指定 [DataMember],因为它假定如果有任何内容是显式的,则一切都是。您可以使用程序集级属性(例如在 AssemblyInfo.cs 中)声明默认命名空间来解决此问题:

[assembly: ContractNamespace("", ClrNamespace = "My.Namespace.Here")]

这解决了命名空间问题。

但是,您无法使用 DataContractSerializer 解决另外 2 个问题:

  • 它不会使用属性(在你的例子中,version)
  • 它要求像item这样的集合有一个包装名和一个元素名(类似于items和item)

您无法解决这些限制,因为 DataContractSerializer 不是通用 XML 解析器。它旨在轻松生成和使用 API,而不是将任意 XML 映射到 .NET 数据结构。你永远不会得到它来解析 rss;因此 ServiceStack.Text(只是包装它)也无法解析它。

改为使用 XmlSerializer

使用XmlSerializer

这是相当直截了当的。您可以按照以下方式解析输入:

var serializer = new XmlSerializer(typeof(RSS));
RSS rss = (RSS)serializer.Deserialize(myXmlReaderHere);

诀窍是注释各个字段,使它们与您的 xml 方言相匹配。例如,在您的情况下是:

[XmlRoot("rss")]
public class RSS
{
[XmlAttribute]
public string version { get; set; }
public ChannelClass channel { get; set; }
}

public class ChannelClass
{
public string title { get; set; }
public string ttl { get; set; }
public string description { get; set; }
public string link { get; set; }
public string copyright { get; set; }
public string language { get; set; }
public string pubDate { get; set; }
[XmlElement]
public List<ItemClass> item { get; set; }
}

public class ItemClass
{
public string title { get; set; }
public string link { get; set; }
public string description { get; set; }
public string guid { get; set; }
}

因此,一些明智的属性足以让它按照您的需要解析 XML。

总结:您不能为此使用 ServiceStack,因为它使用 DataContractSerializer。ServiceStack/DataContractSerializer 专为您控制模式的场景而设计. 改用XmlSerializer

关于c# - 使用 Servicestack.Text 进行 XML 反序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14941190/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com