[英]XML Deserialization with Servicestack.Text
I am learning Servicestack.Text Library as it has some of the best features.I am trying to deserialize XML into one of my DTOs as below; 我正在学习Servicestack.Text库,因为它具有一些最好的功能。我正在尝试将XML反序列化为我的一个DTO,如下所示;
C# Code: [Relevant Code with Console Application Here] 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();
}
}
You can go through the XML file at str
[Given in the program]. 您可以在
str
[程序中的给定]中查看XML文件。 I have prepared DTOs for the deserialization. 我为反序列化准备了DTO。 They are as below:
它们如下:
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; }
}
When I run the program, I get an exception as shown below: 当我运行程序时,我得到一个例外,如下所示:
So, to change the Element
and the namespace
, I did following workaround: 因此,要更改
Element
和namespace
,我做了以下解决方法:
I put the DataContractAttribute
on my Response
class as below: 我把
DataContractAttribute
放在我的Response
类上,如下所示:
[DataContract(Namespace = "")]
public class Response
{
public RSS rss { get; set; }
}
I changed the Element
name as below by adding following two lines just before deserializing 我通过在反序列化之前添加以下两行来更改
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>");
But, it gave another exception on the foreach loop as the deserialized rss
object was null
. 但是,它在foreach循环上给出了另一个例外,因为反序列化的
rss
对象为null
。 So, how should I deserialize it in a proper way using Servicestack.Text
? 那么,我应该如何使用
Servicestack.Text
以适当的方式对其进行反序列化?
Note : 注意 :
I know well how to deserialize with other libraries, I want to do it with ServiceStack only. 我很清楚如何使用其他库进行反序列化,我只想使用ServiceStack。
TLDR: Use XmlSerializer
to deserialize from xml dialects you can't control; TLDR:使用
XmlSerializer
从您无法控制的xml方言反序列化; ServiceStack
is designed for code-first development and can not be adapted to general purpose xml parsing. ServiceStack
专为代码优先开发而设计, 不能适用于通用xml解析。
ServiceStack.Text does not implement a custom Xml serializer - it uses DataContractSerializer
under the hood. ServiceStack.Text 没有实现自定义Xml序列化程序 - 它使用了
DataContractSerializer
。 FromXml
is merely syntactic sugar. FromXml
只是语法糖。
DataContractSerializer
to parse Xml DataContractSerializer
来解析Xml As you've noticed, DataContractSerializer
is picky about namespaces . 正如您所注意到的,
DataContractSerializer
对命名空间很挑剔。 One approach is to specify the namespace explicitly on the class, but if you do this, you'll need to specify [DataMember]
everywhere since it assumes that if anything is explicit, everything is. 一种方法是在类上明确指定命名空间,但是如果这样做,则需要在任何地方指定
[DataMember]
,因为它假定如果有任何内容是明确的,那么一切都是。 You can work around this problem using an assembly-level attribute (eg in AssemblyInfo.cs) to declare a default namespace: 您可以使用程序集级属性(例如在AssemblyInfo.cs中)来解决此问题,以声明默认命名空间:
[assembly: ContractNamespace("", ClrNamespace = "My.Namespace.Here")]
This solves the namespace issue. 这解决了命名空间问题。
However, you cannot solve 2 other issues with DataContractSerializer: 但是,您无法解决DataContractSerializer的其他2个问题:
version
) version
) item
have both a wrapping name and an element name (something like items and item) item
集合具有包装名称和元素名称(类似于项目和项目) You cannot work around these limitations because DataContractSerializer
is not a general-purpose XML parser . 您
DataContractSerializer
这些限制,因为DataContractSerializer
不是通用XML解析器 。 It is intended to easily produce and consume an API, not map arbitrary XML onto a .NET datastructure. 它旨在轻松生成和使用API,而不是将任意XML映射到.NET数据结构。 You will never get it to parse rss;
你永远不会得到它来解析rss; so therefore ServiceStack.Text (which just wraps it) can also not parse it.
因此,ServiceStack.Text(它只包装它)也无法解析它。
Instead, use XmlSerializer
. 相反,使用
XmlSerializer
。
XmlSerializer
XmlSerializer
This is rather straighforward. 这是相当直接的。 You can parse input with something along the lines of:
您可以使用以下内容解析输入:
var serializer = new XmlSerializer(typeof(RSS));
RSS rss = (RSS)serializer.Deserialize(myXmlReaderHere);
The trick is to annotate the various fields such that they match your xml dialect. 诀窍是注释各个字段,使它们与你的xml方言相匹配。 For example, in your case that would be:
例如,在您的情况下,将是:
[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; }
}
So some judicious attributes suffice to get it to parse the XML as you want. 因此,一些明智的属性足以让它根据需要解析XML。
In summary: you cannot use ServiceStack for this since it uses DataContractSerializer
.ServiceStack/ DataContractSerializer
are designed for scenarios where you control the schema. 总结:您不能使用ServiceStack,因为它使用
DataContractSerializer
.ServiceStack / DataContractSerializer
是为您控制架构的场景而设计的。 Use XmlSerializer
instead. 请改用
XmlSerializer
。
A few things: 一些东西:
Since you are using the [DataContract] attribute. 由于您使用的是[DataContract]属性。 You must include the DTOs properties with the [DataMember] Attribute or they will be skipped in the serialization/deserialization process.
必须将DTO属性包含在[DataMember]属性中,否则将在序列化/反序列化过程中跳过它们。 Use the assembly attribute as specified in XML deserializing only works with namespace in xml
使用XML反序列化中指定的assembly属性仅适用于xml中的命名空间
Your xml manipulation needs to change to wrap the rss inside a response instead or replacing it. 您的xml操作需要更改以将rs包装在响应中或替换它。
xml = xml.Replace("<rss version=\\"2.0\\">", "<Response><rss version=\\"2.0\\">");
I would recommend building an test Response object yourself, serlialize it to XML using ServiceStack's .ToXml() method to see the format it is expecting. 我建议您自己构建一个测试Response对象,使用ServiceStack的.ToXml()方法将其serilialize为XML,以查看它期望的格式。 You will see service stack handles the channel items as a child list of items that is not how the RSS formats the channel items.
您将看到服务堆栈将通道项目处理为项目的子列表,而不是RSS格式化通道项目的方式。 You would have to wrap all your items into a node called
<ItemClass>
您必须将所有项目包装到名为
<ItemClass>
的节点中
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.