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

发布于 2024-12-25 12:27:00 字数 982 浏览 2 评论 0 原文

假设我在同一个程序集中有两个不同的 xml 文件作为嵌入资源:

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 类时,它将生成异常。

Suppose I have two different xml files as embedded-resource in a same assembly:

x.xml

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

y.xml

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

And I have two classes Car.cs and Shark.cs to help to deserialize them.

What would be the technique to deserialize them into two different and separate objects?

The following code can handle only one type at a time. Isn't it?

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);
    .... .... ....
}

And, when this code will encounter a Shark-class, it will generate an exception.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

木緿 2025-01-01 12:27:00

为了使系统在任何方面都可靠,您需要为 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, 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);
   }
}

For the system to be reliable in any way you need to namespace your XML (you should always be namespacing XML anyway - but I'll save you the rant). Therefore:

<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>

Your C# XML serialization attributes would then become:

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

Following this you would write something along the lines of a XmlSerializerManager. This would maintain an internal Dictionary<Tuple<string, string>, XmlSerializer> - which you can populate via reflection (look for all types with a XmlRootAttribute applied and create the tuple according to Namespace, LocalName and instantiate the XmlSerializer for that type). This would probably be a static class.

To deserialize any element you simply need to look up its Name and Namespace in the dictionary to retrieve the XmlSerializer instance. For example:

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);
   }
}
做个ˇ局外人 2025-01-01 12:27:00

查看 XmlSerializer 类。来自 MSDN:

将对象序列化到 XML 文档中或从 XML 文档中反序列化对象。这
XmlSerializer 使您能够控制如何将对象编码为 XML。

如果您的类结构与给定的 ML 不完全匹配,即属性名称和 XML 元素之间没有相关性,您将 必须使用属性来提供合适的映射

关于上面的代码,构造了一个 XmlSerializer 实例,以便序列化/反序列化单个类型。您需要创建此类的单独实例,一个用于汽车,一个用于鲨鱼。

Have a look at the XmlSerializer class. From MSDN:

Serializes and deserializes objects into and from XML documents. The
XmlSerializer enables you to control how objects are encoded into XML.

If you class structure doesn't not exactly match the ML given, i.e. there isn't a correlation between property names and XML elements, you will have to use attributes to provide a suitable mapping.

Regarding your code above, an XmlSerializer instance is constructed such that it serializes / de-serializes a single type. You need to create separate instances of this class, one for car one for shark.

空城缀染半城烟沙 2025-01-01 12:27:00

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

我使用这个链接来了解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;
}

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

your code can handle one class only.

i used this link to learn about XMLserializer. here you can find some nice examples. in the last example this code appears:

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;
}

you can rebuild it to use your .xml files in this matter:

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;
}

by calling these 2 function you can get both classes

黯然#的苍凉 2025-01-01 12:27:00

我将创建一个如下所示的抽象基类

 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");

希望这就是您正在寻找的。

托尔斯滕

I would create an abstract base class like the following

 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; }
}

You could easily access the static method from any subclass

Car myCar = Car.GetFromXml("a.xml");
Shark greatWhite = Shark.GetFromXml("b.xml");

Hope that's what you're lookin for.

Thorsten

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文