[英]Alternative for deserializing XML with XmlSerializer
I am programming an UWP app and want to deserialize a list inside a xml to a list of Objects: 我正在编写一个UWP应用程序,并希望将xml中的列表反序列化为对象列表:
<List>
<Element Name="A">
<SubElement Name="A1">
<Color> Blue </Color>
<Color> Red </Color>
</SubElement>
<SubElement Name="A2">
<Color> Blue </Color>
<Color> Green </Color>
</SubElement>
</Element>
<Element Name="B">
<SubElement Name="B1">
<Color> Yellow </Color>
<Color> Red </Color>
</SubElement>
<SubElement Name="B2">
<Color> Yellow </Color>
<Color> Green </Color>
</SubElement>
</Element>
<Element Name="C"/>
<SubElement Name="C1">
<Color> Purple </Color>
<Color> Red </Color>
</SubElement>
<SubElement Name="C2">
<Color> Purple </Color>
<Color> Green </Color>
</SubElement>
</Element>
</List>
The classes look like this: 这些类看起来像这样:
public class Element
{
[XmlAttribute]
public string Name { get; set; }
[XmlElement("SubElement")]
public List<SubElement> _subelement { get; set; }
}
public class SubElement
{
[XmlElement("Color")]
public string Color{ get; set; }
[XmlAttribute("Name")]
public string Name { get; set; }
}
My C# code looks like this: 我的C#代码如下所示:
XDocument doc = XDocument.Load("list.xml");
XElement node = doc.Descendants(XName.Get("List")).FirstOrDefault();
var serializer = new XmlSerializer(typeof(List<Element>), new XmlRootAttribute("List"));
var elementList = serializer.Deserialize(node.CreateReader()) as List<Element>;
In debug mode this application works fine. 在调试模式下,此应用程序正常工作 In release mode I get a
PlatformNotSupportedException
error as in this thread. 在发布模式下,我收到此线程中的
PlatformNotSupportedException
错误。 I found out that the problem must have something to do with the Compile with .NET Native tool chain
Option in the project settings. 我发现问题必须与项目设置中的
Compile with .NET Native tool chain
选项有关。 But I found no solution for the problem. 但我找不到解决问题的办法。
My Question: Is there a simple alternative for the code shown above to deserialize XML to Objects, which doesn't use XmlSerializer and works in an UWP app? 我的问题:上面显示的代码是否有一个简单的替代方法可以将XML反序列化为对象,它不使用XmlSerializer并在UWP应用程序中工作?
In your rewritten question , your XML would seem to have arbitrary complexity with a mixture of elements and attributes. 在您重写的问题中 ,您的XML似乎具有任意复杂性,并且具有元素和属性的混合。 You are seeking a way to deserialize this XML automatically without use of
XmlSerializer
, which basically amounts to writing another XML serializer . 您正在寻找一种在不使用
XmlSerializer
情况下自动反序列化此XML的方法,这基本上相当于编写另一个XML序列化程序 。
Since this is nontrivial (and outside the scope of a stackoverflow answer), one quick workaround would be to translate the XML to a format recognized by some other serializer, and use that. 由于这是非常重要的(并且超出了stackoverflow答案的范围),因此一个快速的解决方法是将XML转换为某些其他序列化程序识别的格式,并使用它。 Possibilities include:
可能性包括:
DataContractSerializer
. DataContractSerializer
。 This serializer is intended for XML deserialization, but does not support: 此序列化程序用于XML反序列化,但不支持:
<Element /><Element/>
) as collections without an outer element. <Element /><Element/>
)作为没有外部元素的集合。 So, while it would be possible to deserialize your XML to some appropriate data model with this serializer, substantial preprocessing using LINQ to XML would be required. 因此,虽然可以使用此序列化程序将XML反序列化为某些适当的数据模型,但仍需要使用LINQ to XML进行大量预处理。
Json.NET . Json.NET 。 This serializer supports conversion of XML to JSON as documented in Converting between JSON and XML and thus may be appropriate to your needs.
此序列化程序支持将XML转换为JSON,如在JSON和XML之间转换中所述 ,因此可能适合您的需要。
If you choose option #2, you could define your data model as follows: 如果选择选项#2,则可以按如下方式定义数据模型:
public class RootObject
{
[JsonConverter(typeof(SingleOrArrayConverter<Element>))]
public List<Element> Element { get; set; }
}
public class Element
{
[XmlAttribute]
[JsonProperty("@Name")]
public string Name { get; set; }
[XmlElement("SubElement")]
[JsonProperty("SubElement")]
[JsonConverter(typeof(SingleOrArrayConverter<SubElement>))]
public List<SubElement> _subelement { get; set; }
}
public class SubElement
{
[XmlElement("Color")]
[JsonConverter(typeof(SingleOrArrayConverter<string>))]
public List<string> Color { get; set; }
[XmlAttribute("Name")]
[JsonProperty("@Name")]
public string Name { get; set; }
}
And deserialize as follows: 并反序列化如下:
var doc = XDocument.Parse(xmlString);
// Convert the XDocument to an intermediate JToken hierarchy.
var converter = new Newtonsoft.Json.Converters.XmlNodeConverter { OmitRootObject = true };
var rootToken = JObject.FromObject(doc, JsonSerializer.CreateDefault(new JsonSerializerSettings { Converters = { converter } }));
// Convert the JTOken to a RootObject
var rootObj = rootToken.ToObject<RootObject>();
Notes: 笔记:
In your question your SubElement
has a single Color
property, but in your XML there are clearly multiple <Color>
elements for each <SubElement>
. 在您的问题中,您的
SubElement
具有单个Color
属性,但在XML中,每个<SubElement>
显然有多个<Color>
元素。 Thus I had to change it to public List<string> Color { get; set; }
因此我不得不将其更改为
public List<string> Color { get; set; }
public List<string> Color { get; set; }
public List<string> Color { get; set; }
. public List<string> Color { get; set; }
。
SingleOrArrayConverter<>
is taken verbatim from this answer to How to handle both a single item and an array for the same property using JSON.net by Brian Rogers . SingleOrArrayConverter<>
是从如何使用 Brian Rogers的 JSON.net处理同一属性的单个项目和数组的 答案中逐字逐句采用的 。 It is needed to handle the case where a single child node is converted to a JSON object rather than a JSON array. 需要处理将单个子节点转换为JSON对象而不是JSON数组的情况。
Working .Net fiddle . 工作.Net小提琴 。
Given the XML shown in the initial version of your question: 鉴于您的问题的初始版本中显示的XML:
<List>
<Element Name="A"/>
<Element Name="B"/>
<Element Name="C"/>
</List>
And assuming your Element
type looks like: 假设您的
Element
类型如下:
public class Element
{
[XmlAttribute]
public string Name { get; set; }
}
Then this type is so simple that you can construct it manually like so: 然后这种类型非常简单,您可以手动构建它,如下所示:
var list = doc
// Get the first elements named List
.Descendants("List").Take(1)
// Get all children of List named Element
.SelectMany(l => l.Elements("Element"))
// Get the attribute of Element named Name, cast its value to a string,
// and create a c# Element from it using the specified name.
.Select(e => new Element { Name = (string)e.Attribute("Name") } )
// Materialize as a List<Element>
.ToList();
Here I am using an explicit casting operator of XAttribute
to convert the Name
attribute to a string value. 这里我使用
XAttribute
的显式转换运算符将Name
属性转换为字符串值。 There are also explicit casting operators for XElement
to convert an element value to a primitive such as a string
, an int
or a nullable DateTime
among others. XElement
还有显式的转换运算符 ,可以将元素值转换为基元,例如string
, int
或可为空的DateTime
等。 These operators can be used when populating ac# type as shown above. 如上所示,在填充ac#类型时可以使用这些运算符。
(Switching to DataContractSerializer
would not be easier since this serializer does not support XML attributes out of the box meaning you would have to do something manual anyway.) (切换到
DataContractSerializer
并不容易,因为此序列化程序不支持开箱即用的XML属性,这意味着您无论如何都必须执行某些操作。)
Sample working .Net fiddle . 样品工作.Net小提琴 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.