基于XML结构设置类的值

时间:2013-01-30 14:28:28

标签: c# linq reflection

我想根据对象中与XML中元素名称相匹配的属性,将XML字符串的某些元素处理到对象中。

XML的示例结构如下:

<Bar>
  <Body>
    <Header>
      <A>Value</A>
      <B>true</B>
    </Header> 
    <Data>
      <D>Value</D>
    </Data>
    <Data>
      <D>Value2</D>
    <Data>  
  </Body>
</Bar>

XML中可能有多个 <Data>个元素,但<Header>只存在一次。我设置的课程如下:

public class Foo
{
  public string A { get; set; }
  public bool B { get; set; }
  public List<FooData> { get; set; }
  public void ProcessXml(string xml)
  {
    XDocument xDoc = XDocument.Load(new StringReader(xml));
    var propVals = (from ele in xDoc.Descendants()
                    join prop in this.GetType().GetProperties() on ele.Name.LocalName equals prop.Name
                    select new
                    {
                      prop = prop,
                      val = new Func<object>(() =>
                        {
                          object objValue = null;
                          prop.PropertyType.TryParse(ele.Value, ref objValue);
                          return objValue;
                        }).Invoke()
                    });
    propVals.ToList().ForEach(x => x.prop.SetValue(this, x.val, null));
  }
}
public class FooData
{
  public string D { get; set; }
}

我提出了开始设置的方法ProcessXml,但是在我只设置Header值(A,B)的那一刻,关于如何添加许多的任何想法很容易在同一方法中将FooData个项目放入List

public static class TypeExtensions
{
  public static void TryParse(this Type t, object valIn, ref object valOut)
  {
    //Do some parsing logic
    try{
      out = TypeDescriptor.GetConverter(t).ConvertFromInvariantString(valIn);
      return true;
    } catch(Exception) { return false; }
  }
}

2 个答案:

答案 0 :(得分:1)

我使用与标题内容类似的行,因为没有一种简单的方法可以将它组合成一行。

var dataElements = (from dataDescendants in (from ele2 in xDoc.Descendants()
                                             Where ele2.Name.LocalName == "Data"
                                             select ele2.Descendants())
                    from dataDescendant in dataDescendants
                    join prop in typeof(FooItem).GetProperties() on prop.Name equals dataDescendant.Name.LocalName
                    select Element = dataDescendant, Property = prop, dataDescendants
                    group by dataDescendants into g = group
                    select g).ToList();
dataElements.ForEach(dataElement =>
                     {
                       FooItem fi = new FooItem();
                       dataElement.ToList.ForEach(x =>
                                                  {
                                                    object objVal = null;
                                                    x.Property.PropertyType.TryParse(x.Element.Value, objVal);
                                                    x.Property.SetValue(fi, objVal, null);
                                                  }
                       DataItems.Add(fi);
                     }

答案 1 :(得分:0)

如果您的XML非常简单,您可以使用序列化来获取此动态/自加载行为,方法是使用适当的XML Serialization attributes来修饰模型类,但每个缩进级别至少需要1个类在文件中:

void Main()
{
    var xml = @"<Bar>
  <Body>
    <Header>
      <A>Value</A>
      <B>true</B>
    </Header> 
    <Data>
      <D>Value</D>
    </Data>
    <Data>
      <D>Value2</D>
    </Data>  
  </Body>
 </Bar>";

    var serializer = new XmlSerializer(typeof(Bar));
    serializer.Deserialize( new MemoryStream( Encoding.ASCII.GetBytes( xml ) ) ).Dump();
}

public class Bar
{
    public Body Body { get; set; }
}

public class Body
{
    public Header Header { get; set; }

    [XmlElement]
    public Data[] Data { get; set; }
}

public class Header
{
    public string A { get; set; }
    public string B { get; set; }
}

public class Data
{
    public string D { get; set; }
}

已编辑:我错过了只有1个标头元素)