在序列化过程中动态控制 XML 元素名称
这是我要解决的问题:我有一个多媒体节目的插件结构,它允许通过从我的框架中的基类进行子类化来实现外部程序集中的媒体类型。节目包含媒体类型列表。使用 XmlSerializer
以 XML 形式加载和保存节目。即使使用插件 MediaTypes 的编程类型映射,这一切都有效。
但是,我希望能够加载包含未知媒体类型的 XML 文件,因为该插件不可用。
为了便于说明,这里有一个这样的 XML 文件:
<MultiMediaShow>
<MediaTypes>
<SomeType />
<SomeType />
<AnotherType />
<UnknownTypeFromPluginNotLoaded />
</MediaTypes>
</MultiMediaShow>
在上面的示例中,我假设 2 个“已知”MediaTypes SomeType
和 AnotherType
,来自 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>
但是,这显然与我反序列化的内容不同。所以问题是,我该如何最好地解决这个问题?!?!
高度赞赏所有帮助!
干杯, Felix
更新
我想知道是否可以以编程方式生成从 UnknownMediaType
派生的类,并且类名取自 UnknownMediaType.XmlTagName
。或者,也可以有一个属性来指定类的 XML 标记名称?
干杯, 菲利克斯
here's my problem to be solved: I've a plugin-structure for multimedia shows that allows to implement media types in external assemblies by subclassing from a base class in my framework. A show holds a list of media types. Shows are loaded and saved in XML using the XmlSerializer
. This all works, even with programatic type mapping for plugin MediaTypes.
However, I want to be able to load XML files that contain MediaTypes that are not known, because the plugin isn't available.
For illustration, here is such an XML file:
<MultiMediaShow>
<MediaTypes>
<SomeType />
<SomeType />
<AnotherType />
<UnknownTypeFromPluginNotLoaded />
</MediaTypes>
</MultiMediaShow>
In the above example, I assume 2 "known" MediaTypes SomeType
and AnotherType
, comming from 2 plugin assemblies. The third type (UnknownTypeFromPluginNotLoaded
) is unknown.
I'm already able to deserialize such unknown objects, but struggle with the serialization. In my aplication, I've the following code so far:
// 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>();
}
When deserializing this with XmlSerializer
, I use the event UnknownElement
and manually insert an UnknownMediaType
element into 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);
}
}
}
The BIG BIG problem is that such an event doesn't seem to be available when serializing an object. What I get as output (not very surpising) is:
<MultiMediaShow>
<MediaTypes>
<SomeType />
<SomeType />
<AnotherType />
<UnknownMediaType /> // !!!! was 'UnknownTypeFromPluginNotLoaded' !!!!
</MediaTypes>
</MultiMediaShow>
However, this is obviously not the same as what I've deserialized. So the question is, how would I best solve this problem?!?!
All help highly appreciated!!
Cheers,
Felix
UPDATE
I was wondering if it is possible to generate classes programmatically that derive from UnknownMediaType
and have the class name taken from the UnknownMediaType.XmlTagName
. Or, alternativly, to have an attribute for specifying the XML tag name of a class??
Cheers,
Felix
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
事实上,我动态地实现了一些基于构建类型的工作解决方案。到目前为止,它正在做我想做的事情。目前我看到的唯一缺点是我将它们创建到当前应用程序域中,因此我无法卸载它们(例如,如果加载新节目或插件在运行时可用)。
这是我的代码:
如果您发布任何与此有关的问题和您的疑虑,我会很高兴...
干杯,
菲利克斯
In fact, I implemented some working solution based on building types dynamically. So far, it's doing what I want. The only downside I see at the moment is that I create them into the current app domain, so I can't unload them (e.g. if a new show is loaded or if the plugins would be made available at runtime).
Here's my code:
Would be glad if you'd post any issues with this and your concerns...
Cheers,
Felix
查看是否可以实现 IXmlSerialized 根类的接口。
来自 MSDN:
See whether you can implement the IXmlSerializable interface for your root class.
From MSDN:
您可以实现客户序列化器。它比使用 xmlserializer 需要更多工作,但可以让您完全控制。请参阅:http://msdn.microsoft.com/ en-us/library/ty01x675(v=vs.80).aspx
You can implement a customer serializer. It is more work than using the xmlserializer, but gives you full control. See: http://msdn.microsoft.com/en-us/library/ty01x675(v=vs.80).aspx