动态地从XElements创建一个列表 [英] Create a List from XElements Dynamically

查看:112
本文介绍了动态地从XElements创建一个列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将一堆XML文件读入XElements列表(实际上是IEnumerable).然后,我想将XElement列表(这些XElement包含一堆子元素)转换为类列表,以便以后可以更轻松地对数据进行操作.

I am reading a bunch of XML files into a list (IEnumerable really) of XElements. Then I want to convert the XElement list (these XElements contain a bunch of child-elements) into a list of classes, so I can do later operations with the data more easily.

现在,如果我事先知道XElements的结构,这将很容易;我只是创建一个模仿XElement结构的类,并用XElement内容填充它的实例.但是这是警告:我的XML文件元素结构与大多数相似,但是可能会有奇数个元素具有不同的结构.为了更好地说明这种情况,让我举个例子.

Now if I know in advance the structure of XElements, this would be easy; I'd just create a class that mimics the XElement structure and fill instances of it with the XElement contents. But here's the caveat; my XML file element structure is mostly similar, but there could be the odd element that has a different structure. To better illustrate the situation let me take an example.

比方说,我的XML文件包含一堆"Person"元素. Person元素具有一些将在所有元素中使用的共同元素,但是有些Person的子代只能在某些元素中找到.

Let's say my XML files contain a bunch of 'Person' elements. The Person elements has some common elements that will be in ALL the elements, but there are some children of Person which can be found only in some of the elements.

例如,所有Person元素都具有以下强制子元素:

For example all Person elements have these mandatory children:

  <Person>
    <Name/>
    <Age/>
    <City/>
    <Country/>
  </Person>

但是,某些Person元素可能包含其他子元素,如下所示:

But, some Person elements may contain additional children as follows:

  <Person>
    <Name/>
    <Age/>
    <City/>
    <Country/>
    <EyeColor/>
    <Profession/>
  </Person>

使情况更糟的是,这些子元素也可以具有几乎类似的结构,但有时会发生变化.

To make things worse, these child elements can also have mostly similar structure that occasionally varies.

那么,有没有一种方法可以让我在一个循环中遍历这些XElement,并将它们放入以某种方式动态创建的实例(例如,基于元素名称或类似名称)?我可以创建一个包含所有必需元素的类,并为奇怪的新元素保留一些其他成员变量,但这并不理想,原因有两个:第一,这将浪费空间,第二,可能会有更多的子元素,而不是我的课堂有额外的变量.

So is there a way that I can go through these XElements in just one loop, and put them into an instance that is somehow dynamically created, say, based on the element names or something similar? I could create a class with all the mandatory elements and leave few additional member variables for the odd new ones, but that's not ideal for two reasons; one, it would be a waste of space, and two, there could be more child element than I have extra variables in my class.

所以我正在寻找一种动态创建类实例以适合XElement结构的方法.换句话说,我真的很想模仿元素结构,直到最深的层次.

So I'm looking for a way to create the class instances dynamically to fit the XElement structure. In other words I'd really like to mimic the element structure right down to the deepest level.

提前谢谢!

推荐答案

我个人认为最好的方法是获得XSD,如果无法获得XSD,则组成一个具有所有可能的可序列化类,然后引用该类. . EG:您有两个字段,其中一个字段有时被设置,而另一个字段您从未见过,但规范可能会在某个地方发生.

I think the best route personally would be to get an XSD, if you cannot get that then make up a serializable class that has all the possibilities and then reference that. EG: You have two fields where one get's set sometimes and one you have never seen set but there is the potential in a spec somewhere it may happen.

因此,让我们组成一个假装类:

So let's make up a pretend class:

using System;
using System.Collections.Generic;
using System.Xml.Serialization;

namespace GenericTesting.Models
{
  [Serializable()]
  public class Location
  {                                                                                
    [XmlAttribute()]
    public int Id { get; set; }
    [XmlAttribute()]
    public double PercentUsed { get; set; }
    [XmlElement]
    public string ExtraGarbage { get; set; }
    [XmlText]
    public string UsedOnceInTheUniverse { get; set; }
  }
}

出于序列化/反序列化的目的,让我为它们提供扩展方法:

And for the purpose of serializing/deserializing let me give extension methods for those:

using System.IO;        
using System.Xml;
using System.Xml.Serialization;

namespace GenericTesting
{                                   
  static class ExtensionHelper
  { 
    public static string SerializeToXml<T>(this T valueToSerialize)
    {
      dynamic ns = new XmlSerializerNamespaces();
      ns.Add("", "");
      StringWriter sw = new StringWriter();

      using (XmlWriter writer = XmlWriter.Create(sw, new XmlWriterSettings { OmitXmlDeclaration = true }))
      {
        dynamic xmler = new XmlSerializer(valueToSerialize.GetType());
        xmler.Serialize(writer, valueToSerialize, ns);
      }

      return sw.ToString();
    }

    public static T DeserializeXml<T>(this string xmlToDeserialize)
    {
      dynamic serializer = new XmlSerializer(typeof(T));

      using (TextReader reader = new StringReader(xmlToDeserialize))
      {
        return (T)serializer.Deserialize(reader);
      }
    }
  }
}

以及控制台应用程序中的一个简单的主入口点:

And a simple main entry point in a console app:

static void Main(string[] args)
{
  var locations = new List<Location>
    {
      new Location { Id = 1, PercentUsed = 0.5, ExtraGarbage = "really important I'm sure"},
      new Location { Id = 2, PercentUsed = 0.6},
      new Location { Id = 3, PercentUsed = 0.7},
    };

  var serialized = locations.SerializeToXml();

  var deserialized = serialized.DeserializeXml<List<Location>>();

  Console.ReadLine();
}

我知道这并不是您所要的,但我个人认为输入正确的类型对于XML更好,并且您与之打交道的任何第三方至少应具有某种类型的规格表或有关其提供的内容的详细信息你.否则,您将失去标准.不应该通过反射或其他方式动态创建Xml,因为这意味着要强制执行严格的键入.

I know this is not exactly what you are asking for but I personally think well typed is better for XML and any third party you ever deal with should have at the very least some type of spec sheet or details on what they are giving you. Else you are losing standards. Xml should not be created from reflection or other means dynamically as it is meant if anything to enforce strict typing if anything.

这篇关于动态地从XElements创建一个列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆