如何在给定 XSD 的情况下在 C# 中进行多态反序列化?

2023-12-12

我给出以下内容:

1) XML 架构、XSD 文件,使用 XSD.EXE 工具编译为 C# 类。

2) RabbitMQ 消息队列,包含 XML 格式中定义的任何类型的格式良好的消息。以下是不同消息的两个片段:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<UserReport xmlns=".../v5.1"; ... >
    ... User report message content... 
</UserReport>

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<CaptureReport xmlns=".../v5.1"; ...>
    ... Capture report message content... 
</CaptureReport>

3) 当类型已知时,有使用 XmlSerializer .Net 类进行反序列化的经验。

问题是当类型未知时如何将消息从 XML 反序列化为对象。无法实例化 XmlSerializer,因为类型未知。

一种方法是循环遍历所有可能的类型,直到反序列化成功,这是一个不好的解决方案,因为 XML 模式中定义了许多不同的类型。

还有其他选择吗?


您可以采取几种方法,具体取决于您在 XML 本身中实现多态性的具体程度。

元素名称是类型名称(反射方式)

您可以像这样获取根元素名称:

string rootElement = null;

using (XmlReader reader = XmlReader.Create(xmlFileName))
{
    while (reader.Read())
    {
        // We won't have to read much of the file to find the root element as it will be the first one found
        if (reader.NodeType == XmlNodeType.Element)
        {
            rootElement = reader.Name;
            break;
        }
    }
}

然后,您可以通过像这样的反射找到类型(如果您的类位于不同的程序集中,则根据需要调整反射):

var serializableType = Type.GetType("MyApp." + rootElement);
var serializer = new XmlSerializer(serializableType);

如果性能很重要,建议您缓存从元素名称到 XML 序列化程序的映射。

元素名称映射到类型名称

如果 XML 元素名称与类型名称不同,或者您不想进行反射,则可以创建一个Dictionary从 XML 中的元素名称映射到XmlSerializer对象,但仍然使用上面的代码片段查找根元素名称。

通过 xsi:type 实现多态的公共根元素

如果您的 XML 消息都具有相同的根元素名称,并且多态性是通过使用 xsi:type 标识类型来实现的,那么您可以执行如下操作:

using System;
using System.Xml.Serialization;

namespace XmlTest
{
    public abstract class RootElement
    {
    }

    public class TypeA : RootElement
    {
        public string AData
        {
            get;
            set;
        }
    }

    public class TypeB : RootElement
    {
        public int BData
        {
            get;
            set;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var serializer = new System.Xml.Serialization.XmlSerializer(typeof(RootElement),
                new Type[]
                {
                    typeof(TypeA),
                    typeof(TypeB)
                });
            RootElement rootElement = null;
            string axml = "<RootElement xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"TypeA\"><AData>Hello A</AData></RootElement>";
            string bxml = "<RootElement xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"TypeB\"><BData>1234</BData></RootElement>";

            foreach (var s in new string[] { axml, bxml })
            {
                using (var reader = new System.IO.StringReader(s))
                {
                    rootElement = (RootElement)serializer.Deserialize(reader);
                }

                TypeA a = rootElement as TypeA;

                if (a != null)
                {
                    Console.WriteLine("TypeA: {0}", a.AData);
                }
                else
                {
                    TypeB b = rootElement as TypeB;

                    if (b != null)
                    {
                        Console.WriteLine("TypeB: {0}", b.BData);
                    }
                    else
                    {
                        Console.Error.WriteLine("Unexpected type.");
                    }
                }
            }
        }
    }
}

注意第二个参数XmlSerializer构造函数,它是您希望 .NET 序列化程序了解的其他类型的数组。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在给定 XSD 的情况下在 C# 中进行多态反序列化? 的相关文章

  • Unix网络编程澄清

    我正在翻阅这本经典书籍Unix网络编程 https rads stackoverflow com amzn click com 0139498761 当我偶然发现这个程序时 第 6 8 节 第 179 180 页 include unp h
  • 如何在 C# 中从 UNIX 纪元时间转换并考虑夏令时?

    我有一个从 unix 纪元时间转换为 NET DateTime 值的函数 public static DateTime FromUnixEpochTime double unixTime DateTime d new DateTime 19
  • 推导指南中的引用和值之间的差异

    考虑类型A template
  • 如何修复此错误“GDI+ 中发生一般错误”?

    从默认名称打开图像并以默认名称保存 覆盖它 我需要从 Image Default jpg 制作图形 将其放在 picturebox1 image 上并在 picurebox1 上绘制一些图形 它有效 这不是我的问题 但我无法保存 pictu
  • 在新的浏览器进程中打开 URL

    我需要在新的浏览器进程中打开 URL 当浏览器进程退出时我需要收到通知 我当前使用的代码如下 Process browser new Process browser EnableRaisingEvents true browser Star
  • XamlReader.Load 在后台线程中。是否可以?

    WPF 应用程序具有从单独的文件加载用户控件的操作 使用XamlReader Load method StreamReader mysr new StreamReader pathToFile DependencyObject rootOb
  • 单元测试一起运行时失败,单独运行时通过

    所以我的单元测试遇到了一些问题 我不能只是将它们复制并粘贴到这里 但我会尽力而为 问题似乎是 如果我一项一项地运行测试 一切都会按预期进行 但如果我告诉它一起运行测试 则 1 5 将通过 TestMethod public void Obj
  • 读取文件特定行号的有效方法。 (奖励:Python 手册印刷错误)

    我有一个 100 GB 的文本文件 它是来自数据库的 BCP 转储 当我尝试导入它时BULK INSERT 我在第 219506324 行上收到一个神秘错误 在解决此问题之前 我想看看这一行 但可惜的是我最喜欢的方法 import line
  • 未经许可更改内存值

    我有一个二维数组 当我第一次打印数组的数据时 日期打印正确 但其他时候 array last i 的数据从 i 0 到 last 1 显然是一个逻辑错误 但我不明白原因 因为我复制并粘贴了 for 语句 那么 C 更改数据吗 I use g
  • PlaySound 可在 Visual Studio 中运行,但不能在独立 exe 中运行

    我正在尝试使用 Visual Studio 在 C 中播放 wav 文件 我将文件 my wav 放入项目目录中并使用代码 PlaySound TEXT my wav NULL SND FILENAME SND SYNC 我按下播放按钮 或
  • 批量更新 SQL Server C#

    我有一个 270k 行的数据库 带有主键mid和一个名为value 我有一个包含中值和值的文本文件 现在我想更新表格 以便将每个值分配给正确的中间值 我当前的方法是从 C 读取文本文件 并为我读取的每一行更新表中的一行 必须有更快的方法来做
  • 私有模板函数

    我有一堂课 C h class C private template
  • HttpWebRequest 在第二次调用时超时

    为什么以下代码在第二次 及后续 运行时超时 代码挂在 using Stream objStream request GetResponse GetResponseStream 然后引发 WebException 表示请求已超时 我已经尝试过
  • 有人可以提供一个使用 Amazon Web Services 的 itemsearch 的 C# 示例吗

    我正在尝试使用 Amazon Web Services 查询艺术家和标题信息并接收回专辑封面 使用 C 我找不到任何与此接近的示例 所有在线示例都已过时 并且不适用于 AWS 的较新版本 有一个开源项目CodePlex http www c
  • .NET中的LinkedList是循环链表吗?

    我需要一个循环链表 所以我想知道是否LinkedList是循环链表吗 每当您想要移动列表中的 下一个 块时 以循环方式使用它的快速解决方案 current current Next current List First 电流在哪里Linke
  • 如何在按钮单击时模拟按键 - Unity

    我对 Unity 中的脚本编写非常陌生 我正在尝试创建一个按钮 一旦单击它就需要模拟按下 F 键 要拾取一个项目 这是我当前的代码 在编写此代码之前我浏览了所有统一论坛 但找不到任何有效的东西 Code using System Colle
  • 编译时“strlen()”有效吗?

    有时需要将字符串的长度与常量进行比较 例如 if line length gt 2 Do something 但我试图避免在代码中使用 魔法 常量 通常我使用这样的代码 if line length gt strlen Do somethi
  • 英特尔 Pin 与 C++14

    问题 我有一些关于在 C 14 或其他 C 版本中使用英特尔 Pin 的问题 使用较新版本从较旧的 C 编译代码很少会出现任何问题 但由于 Intel Pin 是操作指令级别的 如果我使用 C 11 或 C 14 编译它 是否会出现任何不良
  • Linq-to-entities,在一个查询中获取结果+行数

    我已经看到了有关此事的多个问题 但它们已经有 2 年 或更长 的历史了 所以我想知道这方面是否有任何变化 基本思想是填充网格视图并创建自定义分页 所以 我还需要结果和行数 在 SQL 中 这将类似于 SELECT COUNT id Id N
  • 检查Windows控制台中是否按下了键[重复]

    这个问题在这里已经有答案了 可能的重复 C 控制台键盘事件 https stackoverflow com questions 2067893 c console keyboard events 我希望 Windows 控制台程序在按下某个

随机推荐