簡體   English   中英

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

[英]Alternative for deserializing XML with 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>;

在調試模式下,此應用程序正常工作 在發布模式下,我收到線程中的PlatformNotSupportedException錯誤。 我發現問題必須與項目設置中的Compile with .NET Native tool chain選項有關。 但我找不到解決問題的辦法。

我的問題:上面顯示的代碼是否有一個簡單的替代方法可以將XML反序列化為對象,它不使用XmlSerializer並在UWP應用程序中工作?

在您重寫的問題中 ,您的XML似乎具有任意復雜性,並且具有元素和屬性的混合。 您正在尋找一種在不使用XmlSerializer情況下自動反序列化此XML的方法,這基本上相當於編寫另一個XML序列化程序

由於這是非常重要的(並且超出了stackoverflow答案的范圍),因此一個快速的解決方法是將XML轉換為某些其他序列化程序識別的格式,並使用它。 可能性包括:

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

    • XML屬性反序列化
    • 序列的反序列化(例如<Element /><Element/> )作為沒有外部元素的集合。

    因此,雖然可以使用此序列化程序將XML反序列化為某些適當的數據模型,但仍需要使用LINQ to XML進行大量預處理。

  2. Json.NET 此序列化程序支持將XML轉換為JSON,如在JSON和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中,每個<SubElement>顯然有多個<Color>元素。 因此我不得不將其更改為public List<string> Color { get; set; } public List<string> Color { get; set; } public List<string> Color { get; set; }

  • SingleOrArrayConverter<>是從如何使用 Brian Rogers的 JSON.net處理同一屬性的單個項目和數組的 答案中逐字逐句采用的 需要處理將單個子節點轉換為JSON對象而不是JSON數組的情況。

工作.Net小提琴

鑒於您的問題的初始版本中顯示的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還有顯式的轉換運算符 ,可以將元素值轉換為基元,例如stringint空的DateTime等。 如上所示,在填充ac#類型時可以使用這些運算符。

(切換到DataContractSerializer並不容易,因為此序列化程序不支持開箱即用的XML屬性,這意味着您無論如何都必須執行某些操作。)

樣品工作.Net小提琴

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM