我有一个对象结构,我正在尝试序列化为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的各种派生类型的对象,因为它允许我使用反射来匹配2个左右的潜在派生类型中的任何一个,这些类型在首次读入时处于未知的顺序和数量通过我的申请。
这是根元素的集合,使用自定义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()方法中,类型变量被正确设置为派生类型,那么为什么它为基类型和派生类型创建节点级别?我该如何阻止它这样做?
答案 0 :(得分:1)
我认为你的问题出在这一行:
[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
,则可以使用this question的答案。
答案 1 :(得分:0)
您应该可以使用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>