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

时间:2017-12-27 13:52:34

标签: c# uwp xmlserializer

我正在编写一个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应用程序中工作?

2 个答案:

答案 0 :(得分:5)

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

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

  1. DataContractSerializer。此序列化程序用于XML反序列化,但不支持:

    因此,虽然可以使用此序列化程序将XML反序列化为某些适当的数据模型,但仍需要使用LINQ to XML进行大量预处理。

  2. Json.NET。此序列化程序支持将XML转换为JSON,如Converting between JSON and XML中所述,因此可能适合您的需要。

  3. 如果选择选项#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>();
    

    注意:

    工作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 NameXElement属性转换为字符串值。 User还有explicit casting operator将元素值转换为基元,例如explicit casting operatorsstringint等。填充c#类型时可以使用这些运算符,如上所示。

(切换到nullable DateTime并不容易,因为此序列化程序DataContractSerializer意味着您无论如何都必须手动操作。)

示例工作does not support XML attributes out of the box