基于 XML 结构设置类的值

本文关键字:设置 XML 结构 基于 | 更新日期: 2023-09-27 17:56:36

我想根据对象中的属性与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; }
  }
}

基于 XML 结构设置类的值

我沿着与标题内容类似的路线进行,因为没有一种简单的方法可以将其合并为一行。

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);
                     }
如果您的 XML

真的这么简单,您可以使用序列化来获取这种动态/自加载行为,方法是使用适当的 XML 序列化属性修饰模型类,尽管文档中每个缩进级别至少需要 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 个标题元素)

相关文章: