我正在编写一个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>
这些课程如下:
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; }
}
我的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>;
在调试模式下,此应用程序正常工作。在发布模式下,我在this线程中收到PlatformNotSupportedException
错误。我发现问题必须与项目设置中的Compile with .NET Native tool chain
选项有关。但我找不到解决问题的办法。
我的问题:上面显示的代码是否有一个简单的替代方法可以将XML反序列化为对象,它不使用XmlSerializer并在UWP应用程序中工作?
答案 0 :(得分:5)
在您的rewritten question中,您的XML似乎具有任意复杂性,并且具有元素和属性的混合。您正在寻找一种在不使用XmlSerializer
的情况下自动反序列化此XML的方法,这基本上等于编写另一个XML序列化程序。
由于这是非常重要的(并且超出了stackoverflow答案的范围),一个快速的解决方法是将XML转换为某些其他序列化程序识别的格式,并使用它。可能性包括:
DataContractSerializer
。此序列化程序用于XML反序列化,但不支持:
<Element /><Element/>
)反序列化为没有外部元素的集合。
因此,虽然可以使用此序列化程序将XML反序列化为某些适当的数据模型,但仍需要使用LINQ to XML进行大量预处理。
Json.NET。此序列化程序支持将XML转换为JSON,如Converting between JSON and XML中所述,因此可能适合您的需要。
如果选择选项#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; }
}
反序列化如下:
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>();
注意:
在您的问题中,您的SubElement
只有一个Color
属性,但在您的XML中,每个<Color>
显然有多个<SubElement>
个元素。因此,我不得不将其更改为public List<string> Color { get; set; }
。
SingleOrArrayConverter<>
从this answer逐字逐句How to handle both a single item and an array for the same property using JSON.net。需要处理将单个子节点转换为JSON对象而不是JSON数组的情况。
工作Brian Rogers。
答案 1 :(得分:1)
鉴于您问题的initial version中显示的XML:
<List>
<Element Name="A"/>
<Element Name="B"/>
<Element Name="C"/>
</List>
假设您的Element
类型如下:
public class Element
{
[XmlAttribute]
public string Name { get; set; }
}
然后这种类型非常简单,您可以手动构建它:
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();
此处我使用XAttribute
Name
将XElement
属性转换为字符串值。 User
还有explicit casting operator将元素值转换为基元,例如explicit casting operators,string
或int
等。填充c#类型时可以使用这些运算符,如上所示。
(切换到nullable DateTime
并不容易,因为此序列化程序DataContractSerializer
意味着您无论如何都必须手动操作。)