c# - 在序列化过程中动态控制 XML 元素名称

标签 c# serialization xml-serialization xmlserializer

这是我要解决的问题:我有一个多媒体节目的插件结构,它允许通过从我的框架中的基类进行子类化来在外部程序集中实现媒体类型。节目包含媒体类型列表。使用 XmlSerializer 以 XML 形式加载和保存节目。即使使用插件 MediaTypes 的编程类型映射,这一切都有效。

但是,我希望能够加载包含未知媒体类型的 XML 文件,因为该插件不可用。

为了便于说明,这里有一个 XML 文件:

<MultiMediaShow>
    <MediaTypes>
        <SomeType />
        <SomeType />
        <AnotherType />
        <UnknownTypeFromPluginNotLoaded />
    </MediaTypes> 
</MultiMediaShow>

在上面的示例中,我假设 2 个“已知”MediaTypes SomeTypeAnotherType,来自 2 个插件程序集。第三种类型 (UnknownTypeFromPluginNotLoaded) 未知。

我已经能够反序列化此类未知对象,但在序列化方面遇到了困难。在我的应用程序中,到目前为止我有以下代码:

// To be implemented / subclassed by plugin assembly types
public abstract class MediaType
{
}

public class UnknownMediaType : MediaType 
{
    [XmlAnyElement]
    public XmlElement[] UnknownChildElements;
    [XmlAnyAttribute]
    public XmlAttibute[] UnknownAttributes;
    [XmlIgnore]
    public string XmlTagName;   // stores the xml element tag name in the original document
}

[XmlRoot("MultimediaShow")]
public class MultimediaShow
{
    public List<MediaType> MediaTypes = new List<MediaType>();
}

当使用 XmlSerializer 反序列化时,我使用事件 UnknownElement 并手动将 UnknownMediaType 元素插入 show.MediaTypes:

void HandleUnknownElements(Show show, List<XmlElementEventArgs> unknownElementEvents, XmlAttributeOverrides overrides)
{
    // add a root attribute to UnknownMediaType
    XmlAttributes attrs = new XmlAttributes();
    XmlRootAttribute xmlRoot = new XmlRootAttribute(e.Element.Name);
    attrs.XmlRoot = xmlRoot;
    XmlAttributeOverrides o = new XmlAttributeOverrides();
    o.Add(typeof(UnknownMediaObject), attrs);

    // use a new XmlSerializer and a memory stream for deserializting the object as UnknownMediaType.
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(UnknownMediaType), o);
    using (MemoryStream memoryStream = new MemoryStream())
    {
        XmlDocument doc = new XmlDocument();
        doc.AppendChild(doc.ImportNode(e.Element, true));
        doc.Save(memoryStream);
        memoryStream.Position = 0;

        try
        {
            // deserialize the object, store the XML element name and insert it into the chapter
            UnknownMediaType t = xmlSerializer.Deserialize(memoryStream) as UnknownMediaObject;
            t.XmlTagName = e.Element.Name;
            show.MediaTypes.Add(t);
        }
        catch (Exception exc)
        {
            System.Diagnostics.Debug.WriteLine(exc.ToString());
            //return objectType.IsByRef ? null : Activator.CreateInstance(objectType);
        }
    }
}

BIG BIG问题是序列化对象时此类事件似乎不可用。我得到的输出(不是很令人惊讶)是:

<MultiMediaShow>
    <MediaTypes>
        <SomeType />
        <SomeType />
        <AnotherType /> 
        <UnknownMediaType />    // !!!! was 'UnknownTypeFromPluginNotLoaded' !!!!
    </MediaTypes> 
</MultiMediaShow>

但是,这显然与我反序列化的不一样。所以问题是,我该如何最好地解决这个问题?!?!

非常感谢所有帮助!!

干杯, 菲利克斯


更新

我想知道是否可以以编程方式生成从 UnknownMediaType 派生的类,并且类名取自 UnknownMediaType.XmlTagName。或者,也可以有一个属性来指定类的 XML 标记名称?

干杯, 菲利克斯

最佳答案

事实上,我动态地实现了一些基于构建类型的工作解决方案。到目前为止,它正在做我想做的事情。目前我看到的唯一缺点是我将它们创建到当前应用程序域中,因此我无法卸载它们(例如,如果加载新节目或插件在运行时可用)。

这是我的代码:

    void HandleUnknownElements(Show show, List<XmlElementEventArgs> unknownElementEvents, XmlAttributeOverrides overrides)
    {
        foreach (XmlElementEventArgs e in unknownElementEvents)
        {
            // (1) Dynamically create a type that simply inherits from UnknownMediaType 

            AssemblyName assName = new AssemblyName("Show Dynamic Type " + e.Element.Name + " Assembly");
            AssemblyBuilder assBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assName, AssemblyBuilderAccess.Run);
            ModuleBuilder modBuilder = assBuilder.DefineDynamicModule(assBuilder.GetName().Name);

            TypeBuilder typeBuilder = modBuilder.DefineType(e.Element.Name, TypeAttributes.Class | TypeAttributes.Public, typeof(UnknownMediaType));
            Type objectType = typeBuilder.CreateType();


            // (2) Add a root attribute to the type as override

            XmlAttributes attrs = new XmlAttributes();
            XmlRootAttribute xmlRoot = new XmlRootAttribute(e.Element.Name);
            attrs.XmlRoot = xmlRoot;
            XmlAttributeOverrides o = new XmlAttributeOverrides();
            o.Add(objectType, attrs);


            // (3) Use a memory stream for creating a temporary XML document that will be deserialized

            using (MemoryStream memoryStream = new MemoryStream())
            {
                XmlDocument doc = new XmlDocument();
                doc.AppendChild(doc.ImportNode(e.Element, true));
                doc.Save(memoryStream);
                memoryStream.Position = 0;


                // (4) Deserialize the object using an XmlSerializer and add it

                try
                {
                    XmlSerializer xmlSerializer = new XmlSerializer(objectType, o);
                    UnknownMediaType t = xmlSerializer.Deserialize(memoryStream) as UnknownMediaType;
                    show.MediaTypes.Add(t);
                }
                catch (Exception exc)
                {
                    System.Diagnostics.Debug.WriteLine(exc.ToString());
                }
            }
        }
    }

如果您发布任何与此有关的问题和您的疑虑,我们将很高兴...

干杯, 菲利克斯

关于c# - 在序列化过程中动态控制 XML 元素名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6534717/

相关文章:

c# - Properties.Settings 没有二传手

c# - 在 WPF 中,您可以在没有代码隐藏的情况下过滤 CollectionViewSource 吗?

c# - 应用关闭后调用函数

java - 如何在 Java 中使用/反序列化 .Net WCF 服务 JSON 响应

java - 根据 GSON 中的值从序列化中排除某些字段

c# - 将 XmlSerializer 与根元素中的数组一起使用

c# - C# 中的 XML 到 SQL 中的 varbinary 列

c# - HttpClient 不使用 ServicePointManager 服务点

c# - 使用 Protobuf-net 跨多个命名空间序列化

java - 如何使用 JAXB 序列化非原始数据?