[英]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
定義 POCO 對象
[ChoXmlRecordObject] public class Root { [ChoXmlNodeRecordField(XPath = "//property1")] public string[] Properties { get; set; } [ChoXmlNodeRecordField(XPath = "//amount/*")] public double[] Amounts { get; set; } }
使用 xml reader 對象反序列化它
var rec = ChoXmlReader.Deserialize<Root>("*** Xml File Path ***").FirstOrDefault(); Console.WriteLine(rec.Dump());
免責聲明:我是這個庫的作者。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.