簡體   English   中英

XmlSerializer 反序列化具有不同元素名稱的列表

[英]XmlSerializer deserializing list with different element names

我正在嘗試使用 XmlSerializer 解析具有如下所示元素的 XML。 在 amount 元素下有很多貨幣類型,我想將它們反序列化為一個對象集合,這些對象具有保存貨幣類型的字符串屬性和保存金額的整數屬性。

是否有任何干凈的方法可以做到這一點而不必自定義解析數量。 我只想將 XmlSerializer 屬性應用於我的類並獲得一些有用的東西。

我無法控制輸出 XML。

<root>
 <property1>a</property1>
 <property1>b</property1>
 <property1>c</property1>
 <amount>
  <EUR type="integer">1000</EUR>
  <USD type="integer">1100</USD>
 </amount>
<root>

攻擊 XML 反序列化的最佳方法是從序列化開始 為此,這里有一些具有控制 XML 序列化屬性的類:

public sealed class root
{
    [XmlElement("property1")]
    public List<string> property1;

    [XmlArrayItem(Type = typeof(EUR))]
    [XmlArrayItem(Type = typeof(USD))]
    public List<amount> amount;
}

public abstract class amount
{
    [XmlAttribute]
    public string type { get; set; }

    [XmlText]
    public string Value { get; set; }
}

public sealed class EUR : amount { }
public sealed class USD : amount { }

測試代碼為:

        var root = new root { property1 = new List<string>(), amount = new List<amount>() };
        root.property1.AddRange(new[]{ "a", "b", "c"});
        var eur = new EUR { type = "integer", Value = "1000" };
        var usd = new USD { type = "integer", Value = "1100" };
        root.amount.AddRange(new amount[]{ eur, usd});

生成以下 XML:

<?xml version="1.0" encoding="utf-16"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <property1>a</property1>
  <property1>b</property1>
  <property1>c</property1>
  <amount>
    <EUR type="integer">1000</EUR>
    <USD type="integer">1100</USD>
  </amount>
</root>

我認為最好的辦法是進行部分 XML 解析,並將<amount>元素的內容保留為XmlElement的集合。 您仍然需要手動解析它,但您只需手動解析該部分 例子:

[XmlRoot("root")]
public class RecordInfo
{
    [XmlElement("property1")]
    public List<string> Property1;

    [XmlElement("amount")]
    public AmountRawData AmountData;
}

public class AmountRawData
{
    [XmlAnyElement]
    public List<XmlElement> Content;

    public IEnumerable<AmountInfo> Parse()
    {
        foreach (var element in this.Content)
        {
            yield return
                new AmountInfo()
                {
                    Currency = element.LocalName,
                    Type = element.GetAttribute("type"),
                    Amount = element.InnerText,
                };
        }
    }
}

public class AmountInfo
{
    public string Currency;
    public string Type;
    public string Amount;
}

用法示例:

var serializer = new XmlSerializer(typeof(RecordInfo));

var result = (RecordInfo)serializer.Deserialize(dataStream);

foreach (var amount in result.AmountData.Parse())
    Console.WriteLine($"{amount.Currency} {amount.Type} {amount.Amount}");

上周使用 xml linq 回答了一個類似的問題:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);

            var results = doc.Elements().Select(x => new {
                property1 = x.Elements("property1").Select(y => (string)y).ToList(),
                dictCurrency = x.Elements("amount").Elements().GroupBy(y => y.Name.LocalName, z => (int)z)
                   .ToDictionary(y => y.Key, z => z.FirstOrDefault())
            }).FirstOrDefault();

        }
    }
}

這是使用Cinchoo ETL 的另一種方法 - 一個開源庫,用於反序列化如下 XML

  1. 定義 POCO 對象

    [ChoXmlRecordObject] public class Root { [ChoXmlNodeRecordField(XPath = "//property1")] public string[] Properties { get; set; } [ChoXmlNodeRecordField(XPath = "//amount/*")] public double[] Amounts { get; set; } }
  2. 使用 xml reader 對象反序列化它

     var rec = ChoXmlReader.Deserialize<Root>("*** Xml File Path ***").FirstOrDefault(); Console.WriteLine(rec.Dump());

免責聲明:我是這個庫的作者。

暫無
暫無

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

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