如何在C#中将两个不同的xmls文件反序列化为两个不同的类对象?

时间:2012-01-05 08:29:16

标签: c#-2.0 xml-deserialization

假设我在同一个程序集中有两个不同的xml文件作为embedded-resource:

x.xml

<car brand="Hummer">
    <type ... />
    <chasis ... />
</car>

y.xml

<shark species="HammerHead">
    <color ... />
    <maxLen .... />
</shark>

我有两个课程Car.csShark.cs来帮助反序列化它们。

将它们反序列化为两个不同且独立的对象的技术是什么?

以下代码一次只能处理一种类型。不是吗?

string[] manifestResourceNames = assembly.GetManifestResourceNames();        
foreach (string mrn in manifestResourceNames)
{
    Stream stream = assembly.GetManifestResourceStream(mrn);
    XmlSerializer serializer = new XmlSerializer(typeof(Car));
    Car car = (Car)serializer.Deserialize(stream);
    .... .... ....
}

并且,当此代码遇到Shark - 类时,它将生成异常。

4 个答案:

答案 0 :(得分:2)

为了使系统以任何方式可靠,您需要命名XML(无论如何,您应始终使用命名空间XML - 但我会为您节省咆哮)。因此:

<car xmlns="http://schemas.cars.org/car" brand="Hummer">
  <type /> <chassis />
</car>
<shark xmlns="http://schemas.ocenia.org/predator">
  <lazer-beams>1</lazer-beams>
  <awesome>Hell yeah.</awesome>
</shark>

您的C#XML序列化属性将变为:

[XmlRoot("Car", Namespace=CarNamespaceUri)]
public class Car
{
   public const string CarNamespaceUri = "http://schemas.cars.org/car";
   // ...
}

在此之后你会写一些XmlSerializerManager的内容。这将保留内部Dictionary<Tuple<string, string>, XmlSerializer> - 您可以通过反射填充(查找应用了XmlRootAttribute的所有类型,并根据Namespace, LocalName创建元组并实例化XmlSerializer那种类型)。这可能是一个静态类。

要反序列化任何元素,只需在字典中查找其名称和命名空间即可检索XmlSerializer实例。例如:

public static T Deserialize<T>(XElement element)
{
   return (T)Deserialize(element);
}

public static object Deserialize(XElement element)
{
   // Remember to do more elaborate checks etc.
   using(var r = element.CreateReader())
   {
       return _serializers[Tuple.Create(element.Name.NamespaceName, element.Name.LocalName)].Deserialize(r);
   }
}

答案 1 :(得分:1)

查看XmlSerializer课程。来自MSDN:

  

将对象序列化和反序列化到XML文档中或从XML文档中反序列化。该   XmlSerializer使您可以控制对象如何编码为XML。

如果类结构与给定的ML不完全匹配,即属性名称和XML元素之间没有关联,则have to use attributes to provide a suitable mapping

关于上面的代码,构造XmlSerializer实例,使其序列化/反序列化单个类型。你需要创建这个类的单独实例,一个用于汽车,一个用于鲨鱼。

答案 2 :(得分:0)

您的代码只能处理一个类。

我使用此link来了解XMLserializer。在这里你可以找到一些很好的例子。在最后一个示例中,此代码显示为:

static List<Movie> DeserializeFromXML()
{
    XmlSerializer deserializer = new XmlSerializer(typeof(List<Movie>));
    TextReader textReader = new StreamReader(@"C:\movie.xml");
    List<Movie> movies;
    movies = (List<Movie>)deserializer.Deserialize(textReader);
    textReader.Close();

    return movies;
}

你可以重建它以使用你的.xml文件:

static List<Car> DeserializeCar()
{
    XmlSerializer deserializer = new XmlSerializer(typeof(List<Car>));
    TextReader textReader = new StreamReader("./car.xml");
    List<Car> cars;
    cars= (List<Car>)deserializer.Deserialize(textReader);
    textReader.Close();

    return cars;
}
static List<Car> DeserializeShark()
{
    XmlSerializer deserializer = new XmlSerializer(typeof(List<Shark>));
    TextReader textReader = new StreamReader("./shark.xml");
    List<Shark> shark;
    shark= (List<Shark>)deserializer.Deserialize(textReader);
    textReader.Close();

    return shark;
}

通过调用这两个函数,您可以获得两个类

答案 3 :(得分:0)

我会创建一个类似于以下

的抽象基类
 public abstract class Model<T>
 {
    public static T GetFromXml(String path)
    {
        if (!File.Exists(path))
            return null;
        var serializer = new XmlSerializer(typeof(T));
        return (T)serializer.Deserialize(File.OpenRead(path));
    }
 }

public class Car : Model<Car>
{
    public String Brand { get; set; }
    public String Type { get; set; }
    public String Chasis { get; set; }
}

public class Shark : Model<Shark>
{
    public String Species { get; set; }
    public String Color { get; set; }
    public long MaxLength { get; set; }
}

您可以从任何子类

轻松访问静态方法
Car myCar = Car.GetFromXml("a.xml");
Shark greatWhite = Shark.GetFromXml("b.xml");

希望这就是你所期待的。

和Thorsten