我正在尝试使用XmlSerializer解析具有如下所示元素的XML。在amount元素下有很多货币类型,我想将它们反序列化为一个对象集合,这些对象具有保存货币类型的字符串属性和保存金额的整数属性。
有没有任何干净的方法来做到这一点,而无需自定义解析金额。我想将XmlSerializer属性应用于我的类并获得有效的东西。
我无法控制输出XML。
two_factor_recovery_codes
答案 0 :(得分:1)
我认为最好的办法是进行部分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}");
答案 1 :(得分:0)
正如我在评论中提到的,攻击XML反序列化的最佳方法是从序列化开始。为此,这里有一些属性为control XML serialization的类:
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>
答案 2 :(得分:0)
这是使用 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());
免责声明:我是这个库的作者。
答案 3 :(得分:-1)
上周使用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();
}
}
}