Xml反序列化 - 将两个元素合并为一个List <t>对象

时间:2016-05-18 18:10:33

标签: c# xml list deserialization xml-deserialization

我有一个XML文档,使用反序列化,有没有办法将两个元素组合成一个对象?

XML示例:

$(document).ready(function(){
    get = document.getElementsByClassName('imgs');
    for(var i=0; i < get.length; i++){
        oldH = get[i].naturalHeight;
        oldW = get[i].naturalWidth;
        divH = "500";
        if(oldH > divH){
            newH = divH;
            calW = newH / oldH;
            newW = calW * oldW; 
        get[i].height = newH;
        get[i].width = newW;
        console.log(newH, newW);
        } else {
            newH = oldH;
            newW = oldW;
        get[i].height = newH;
        get[i].width = newW;
        console.log(newH, newW);
        }   
    }
});

我想创建一个列表(类型为Parameter),其中包含3和4项。

我尝试过使用XmlArrayItem,例如:

<Parameter1>3</Parameter1>
<Parameter2>4</Parameter2>

我尝试过使用XmlElements(但我无法弄清楚如何将它们组合起来):

[XmlArrayItem("Parameter1")]
[XmlArrayItem("Parameter2")]
[XmlArray]
public Parameter[] Parameters; // have also tried this as public List<Parameter> Parameters = new List<Parameter>();

如果不创建两个单独的列表并在以后合并它们,有没有办法做到这一点?

请注意,更改XML格式不是一种选择。

2 个答案:

答案 0 :(得分:1)

您的XML具有包含choice元素的架构。 choice元素表示在您的情况下,一组固定的元素 - <Parameter1><Parameter2>将出现在XML中。 XmlSerializer支持选择元素,如Choice Element Binding Support中所述:

  

如果个人选择元素&#39;类型与其名称不同,Xsd.exe仅将XmlElementAttribute属性应用于公共成员。如果它们仅按名称不同,则Xsd.exe另外应用XmlChoiceIdentifierAttribute,并添加额外的逻辑以进行选择。

因此,您可以使用以下选项反序列化XML:

  1. Parameter类进行子类化,并使用[XmlElementAttribute(String, Type)]为每个元素名称指定不同的类型。因此,实例化的特定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; }
    }
    
  2. 如果要使用相同的Parameter类型反序列化<Parameter1><Parameter2>元素,则必须引入辅助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数组将具有与Parameters数组相同的条目数,其中的enum值将指示每个参数实际遇到的XML元素名称。

  3. 作为选项2的变体,如果您不需要捕获XML元素名称并且只想反序列化值,则可以创建一个&#34; fake&#34;选择数组属性如下:

    [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.
            }
        }
    }
    
  4. XmlSerializer要求您使用这两个选项之一。如果它无法按类型或项目选择标识符确定正确的元素名称,它将抛出InvalidOperationException消息:

    You need to add XmlChoiceIdentifierAttribute to the 'Parameters' member.
    

    原型fiddle显示每个选项。

答案 1 :(得分:0)

如果你这样做会怎么样:

//get the xml doc
const string str = @"<root>
                       <Parameter1>3</Parameter1>
                       <Parameter2>4</Parameter2>
                     </root>";

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<Parameter>();

//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; }  
}