XML序列化导致重复节点
本文关键字:节点 序列化 XML | 更新日期: 2023-09-27 18:18:57
我有一个对象结构,我试图序列化到xml,导致重复的节点级别。我很确定它与子类化有关,因为我必须实现我自己的反序列化,但我不确定在另一个方向上到底发生了什么。当在应用程序启动时反序列化我的数据时,使用相同的xml结构作为输入,当重新序列化它以稍后保存时。
下面是错误输出xml的样子:
<Keyboarding xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Exercises>
<Exercise>
<Exercise Id="3" ActivityNumber="5" SubActivityNumber="b" Type="Standard">
<Title>Test Title</Title>
<Instructions>Downloaded Update Instructions</Instructions>
</Exercise>
</Exercise>
</Exercises>
</Keyboarding>
它应该是这样的(以及初始反序列化时的样子):
<Keyboarding xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Exercises>
<Exercise Id="3" ActivityNumber="5" SubActivityNumber="b" Type="Standard">
<Title>Test Title</Title>
<Instructions>Downloaded Update Instructions</Instructions>
</Exercise>
</Exercises>
</Keyboarding>
根对象包含一个练习集合。Exercise是我的基类,而子类由Type属性决定。我使用自定义xml序列化器来构建来自Exercise的不同派生类型的对象,因为它允许我使用反射来匹配大约24种潜在派生类型中的任何一种,这些类型在应用程序第一次读取时顺序和数量未知。
下面是根元素的集合,使用自定义xml序列化器:
[XmlArray("Exercises")]
[XmlArrayItem("Exercise", Type = typeof (ExerciseXmlSerializer<Exercise>))]
public Collection<Exercise> UnprocessedExercises { get; set; }
我的基本练习类声明如下:
[Serializable]
[XmlType(AnonymousType = true)]
public class Exercise
我的派生类声明如下:
[Serializable]
[XmlType(AnonymousType = true)]
[XmlRoot(ElementName = "Exercise", IsNullable = false)]
public class StandardExercise : Exercise
这是我的自定义xml序列化器的写入器部分:
public class ExerciseXmlSerializer<T> : IXmlSerializable where T : class
{
private T _data;
...
public void WriteXml(XmlWriter writer)
{
Type type = _data.GetType();
new XmlSerializer(type).Serialize(writer, _data);
}
...
}
在WriteXml()方法中,类型变量被正确地设置为派生类型,那么为什么要为基类型和派生类型创建节点级别呢?我如何防止它这样做?
我想你的问题出在这一行:
[XmlArrayItem("Exercise", Type = typeof (ExerciseXmlSerializer<Exercise>))]
我不认为您想要指出项的类型是序列化器的类型。如果要实现IXmlSerializable,它需要在要序列化的类上。
我要做的是:
public class Keyboarding
{
[XmlArray("Exercises")]
[XmlArrayItem("Exercise")]
public Collection<Exercise> UnprocessedExercises { get; set; }
public Keyboarding()
{
UnprocessedExercises = new Collection<Exercise>();
UnprocessedExercises.Add(new StandardExercise());
}
}
[XmlInclude(typeof(StandardExercise))]
public class Exercise
{
}
[Serializable]
public class StandardExercise : Exercise
{
}
生成的输出类似如下:
<?xml version='"1.0'"?>
<Keyboarding xmlns:xsi='"http://www.w3.org/2001/XMLSchema-instance'" xmlns:xsd='"http://www.w3.org/2001/XMLSchema'">
<Exercises>
<Exercise xsi:type='"StandardExercise'" />
</Exercises>
</Keyboarding>
如果您不希望在输出中包含xsi:type
,您可以使用此问题的答案
你应该能够使用XmlAttributeOverrides来做你想要的。在这种情况下,你可能会这样做。示例代码有点粗糙,因为您没有包含整个对象图,但希望这将为您指明正确的方向。
List<Type> extraTypes = new List<Type>();
XmlAttributes attrs = new XmlAttributes();
extraTypes.Add(typeof(Exercise));
extraTypes.Add(typeof(StandardExercise));
XmlElementAttribute attr = new XmlElementAttribute
{
ElementName = "Exercise",
Type = typeof(Exercise)
};
attrs.XmlElements.Add(attr);
attr = new XmlElementAttribute
{
ElementName = "StandardExercise",
Type = typeof(StandardExercise)
};
attrs.XmlElements.Add(attr);
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
overrides.Add(typeof(Keyboarding), "Keboarding", attrs);
return new XmlSerializer(typeof(Keyboarding), overrides, extraTypes.ToArray(),
new XmlRootAttribute("Keyboarding"), string.Empty);
这应该允许您创建如下所示的XML树。这和你想要的不太一样,但同样具有描述性。
<Keyboarding xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Exercises>
<StandardExercise Id="3" ActivityNumber="5" SubActivityNumber="b">
<Title>Test Title</Title>
<Instructions>Downloaded Update Instructions</Instructions>
</StandardExercise >
</Exercises>
</Keyboarding>