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

我正在尝试使用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:temptest.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();

        }
    }
}
链接地址: http://www.djcxy.com/p/54907.html

上一篇: XmlSerializer deserializing list with different element names

下一篇: Deserialize random/unknown types with XmlSerializer