1

我想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; }
  }
}
4

2 回答 2

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);
                     }
于 2013-01-31T11:29:11.303 回答
0

如果您的 XML 真的那么简单,您可以使用序列化来获得这种动态/自加载行为,方法是使用适当的XML 序列化属性装饰您的模型类,尽管对于文档中的每一级缩进至少需要一个类:

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 个 Header 元素)

于 2013-01-30T15:05:26.467 回答