Xml反序列化 – 将两个元素合并为一个List 对象
我有一个XML文档,并使用反序列化,有没有办法将两个元素组合成一个对象?
XML示例:
3 4
我想创建一个包含项目3和4的列表(类型为Parameter)。
我尝试过使用XmlArrayItem,例如:
[XmlArrayItem("Parameter1")] [XmlArrayItem("Parameter2")] [XmlArray] public Parameter[] Parameters; // have also tried this as public List Parameters = new List();
我尝试过使用XmlElements(但我无法弄清楚如何将它们组合起来):
[XmlElement("Parameter1")] public List Parameters = new List();
有没有办法做到这一点,而不只是创建两个单独的列表,并在以后组合它们?
请注意,更改XML格式不是一种选择。
如果你这样做会怎么样:
//get the xml doc const string str = @" 3 4 "; var xml = new XmlDocument(); //load it xml.LoadXml(str); //get the nodes where the names contain the string parameter var xnList = xml.SelectNodes("//*[contains(name(),'Parameter')]"); //create a list of parameters var list = new List(); //populate the list with the value in the node's innertext foreach (XmlNode xn in xnList) { list.Add(new Parameter{ Value = int.Parse(xn.InnerText) } ); } foreach(var param in list) Console.WriteLine(param.Value); //should print 3 and 4
我使用这个类作为例子:
class Parameter{ public int Value { get; set; } }
您的XML具有包含choice元素的架构。 一个choice元素表示一个固定的元素集 – 在你的情况下是
和
– 将出现在XML中。 XmlSerializer
支持选择元素,如选择元素绑定支持中所述 :
如果各个选项元素的类型及其名称不同,则Xsd.exe仅将
XmlElementAttribute
属性应用于公共成员。 如果它们仅按名称不同,则Xsd.exe另外应用XmlChoiceIdentifierAttribute
,并添加额外的逻辑以进行选择。
因此,您可以使用以下选项反序列化XML:
-
使用
[XmlElementAttribute(String, Type)]
为您的Parameter
类子类化并为每个元素名称指定不同的类型。 因此,实例化的特定Parameter
子类将捕获XML元素名称。即你能做到:
public abstract class Parameter { [XmlText] public string Value { get; set; } // Could be int if you prefer. } public class Parameter1 : Parameter { } public class Parameter2 : Parameter { } [XmlType("Root")] public class RootObject { [XmlElement("Parameter1", typeof(Parameter1))] [XmlElement("Parameter2", typeof(Parameter2))] public Parameter[] Parameters { get; set; } }
-
如果要使用相同的
Parameter
类型对
和
元素进行反序列化,则必须引入辅助XmlChoiceIdentifierAttribute
数组以捕获XML元素名称:public class Parameter { [XmlText] public string Value { get; set; } } [XmlType("Root")] public class RootObject { [XmlElement("Parameter1", typeof(Parameter))] [XmlElement("Parameter2", typeof(Parameter))] [XmlChoiceIdentifier("ParametersElementName")] public Parameter[] Parameters { get; set; } [XmlIgnore] public ParametersChoiceType[] ParametersElementName { get; set; } } [XmlType(IncludeInSchema = false)] public enum ParametersChoiceType { Parameter1, Parameter2, }
反序列化后,
ParametersElementName
数组将具有与ParametersElementName
数组相同数量的条目,其中的enum
值将指示实际遇到的每个参数的XML元素名称。 -
作为选项2的变体,如果您不需要捕获XML元素名称并且只想反序列化值,则可以创建“假”选择数组属性,如下所示:
[XmlType("Root")] public class RootObject { [XmlElement("Parameter1", typeof(Parameter))] [XmlElement("Parameter2", typeof(Parameter))] [XmlChoiceIdentifier("ParametersElementName")] public Parameter[] Parameters { get; set; } [XmlIgnore] public ParametersChoiceType[] ParametersElementName { get { if (Parameters == null) return null; return Parameters.Select(p => ParametersChoiceType.Parameter1).ToArray();// Arbitrarily return ItemsChoiceType.Parameter1 } set { // Do nothing - don't care. } } }
XmlSerializer
要求您使用这两个选项之一。 如果它无法按类型或项目选项标识符确定正确的元素名称,则会抛出带有以下消息的InvalidOperationException
:
You need to add XmlChoiceIdentifierAttribute to the 'Parameters' member.
原型小提琴显示每个选项。