使用XmlSerializer反序列化XML的替代方法

问题描述 投票:3回答:2

我正在编写一个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>;

在调试模式下,此应用程序正常工作在发布模式下,我在PlatformNotSupportedException线程中得到this错误。我发现问题必须与项目设置中的Compile with .NET Native tool chain选项有关。但我找不到解决问题的办法。

我的问题:上面显示的代码是否有一个简单的替代方法可以将XML反序列化为对象,它不使用XmlSerializer并在UWP应用程序中工作?

c# uwp xmlserializer
2个回答
5
投票

在你的rewritten question中,你的XML似乎具有任意复杂性,混合了元素和属性。您正在寻找一种在不使用XmlSerializer的情况下自动反序列化此XML的方法,这基本上相当于编写另一个XML序列化程序。

由于这是非常重要的(并且超出了stackoverflow答案的范围),因此一个快速的解决方法是将XML转换为某些其他序列化程序识别的格式,并使用它。可能性包括:

  1. DataContractSerializer。此序列化程序用于XML反序列化,但不支持: XML attribute deserialization。 将序列(例如<Element /><Element/>)反序列化为没有外部元素的集合。 因此,虽然可以使用此序列化程序将XML反序列化为某些适当的数据模型,但仍需要使用LINQ to XML进行大量预处理。
  2. 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>();

笔记:

工作.Net fiddle


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();

在这里,我使用explicit casting operatorXAttributeName属性转换为字符串值。 explicit casting operators还有XElement将元素值转换为原始元素,如stringintnullable DateTime等。填充c#类型时可以使用这些运算符,如上所示。

(切换到DataContractSerializer并不容易,因为这个序列化器does not support XML attributes out of the box意味着你无论如何都要做一些手动操作。)

样本工作.Net fiddle

© www.soinside.com 2019 - 2024. All rights reserved.