这是我的问题。我有一个父类“Foo”和一个子类“Bar”:
[Serializable]
public class Foo, IXmlSerializable
{
public Bar Child {get; set;}
#region IXmlSerializable Membres
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
throw new NotImplementedException();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
new XmlSerializer(this.Child.GetType()).Serialize(writer, this.Child);
}
#endregion
}
[Serializable]
public class Bar
{
[XmlElement]
public string MyElement1 {get; set;}
[XmlElement]
public string MyElement2 {get; set;}
}
如果我将这些类序列化,我将会得到类似的结果:
<xml>
<Foo>
<Bar>
<MyElement1>beer</MyElement>
<MyElement2>vodka</MyElement>
</Bar>
</Foo>
但是,如何从“Foo”(父)类控制序列化以删除“Bar”节点。我希望有类似的东西:
<xml>
<Foo>
<MyElement1>beer</MyElement>
<MyElement2>vodka</MyElement>
</Foo>
这个样本非常简单。 谢谢你的帮助!
答案 0 :(得分:1)
您需要更改Foo
的{{1}}方法并执行以下操作:
WriteXml
这将呈现您正在寻找的XML(基本上使public void WriteXml(System.Xml.XmlWriter writer)
{
//new XmlSerializer(this.Child.GetType()).Serialize(writer, this.Child);
writer.WriteElementString("MyElement1", this.Child.MyElement1);
writer.WriteElementString("MyElement2", this.Child.MyElement2);
}
节点消失)。
答案 1 :(得分:0)
@Marc:解释起来很复杂,我只需要它......
我想我找到了办法。也许不是最好的,但也不是最糟糕的...感谢您的帮助!
public void WriteXml(System.Xml.XmlWriter writer)
{
if (this.Child != null)
{
XmlSerializer xs = new XmlSerializer(typeof(Bar));
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "http://www.w3.org/2001/XMLSchema-instance");
ns.Add("", "http://www.w3.org/2001/XMLSchema");
XElement res = SerializeAsXElement(xs, this.Child, ns);
MoveDescendants(res, writer);
// new XmlSerializer(this.InitRes.GetType()).Serialize(writer, this.InitRes);
}
}
#endregion
/// <summary>
/// Moves all the children of src (including all its elements and attributes) to the
/// destination element, dst.
/// </summary>
/// <param name="src">The source element.</param>
/// <param name="dst">The destination element.</param>
public static void MoveDescendants(XElement src, XmlWriter dst)
{
foreach (XAttribute attr in src.Attributes())
{
dst.WriteAttributeString(attr.Value, attr.Name.LocalName);
}
foreach (XNode elem in src.Nodes())
{
elem.WriteTo(dst);
}
}
public static XElement SerializeAsXElement(XmlSerializer xs, object o, XmlSerializerNamespaces ns)
{
XDocument d = new XDocument();
using (XmlWriter w = d.CreateWriter()) xs.Serialize(w, o, ns);
XElement e = d.Root;
e.Remove();
return e;
}
答案 2 :(得分:0)
我不确定什么情况会导致你要求这个,它确实感觉不对,但是现在我只是假设你有正当的理由。
如果你在Bar上实现IXmlSerializable并使用Foo代理而不是使用XmlSerializer那么这应该可以得到你想要的东西......它只是意味着你放弃了在Bar上使用序列化属性的便利。
答案 3 :(得分:0)
这里的技巧是使用这两种机制来进行序列化和反序列化。
在下面的示例中,我有一个类型为Foo的List,它是一个具有抽象子元素的IXmlSerializable。每个具体的子项都使用更整洁的属性来实现序列化。
对于写作,Foos WriteXml会写出一个元素,其名称是契约子元素的完整类型名称。然后它将孩子序列化。
对于阅读,Foos ReadXml做了一些难看的读取,将自己定位在全名的位置,并创建具体类型的新实例(但请注意,Foo不知道所有可能的具体类型) 然后,它根据具体类型创建一个新的XmlSerializer并对其进行反序列化。 同样,它需要做一些丑陋的读取来为读者定位下一个元素。
这将生成以下XML
String str="country_province_city";
wordUtils.capitalize(str, '_');
str=str.replaceAll("_", "");
代码是:
<?xml version="1.0"?>
<ArrayOfFoo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Foo>
<ParentData>a</ParentData>
<XmlAbstractSerialisationTest.Bar1>
<Bar1>
<Id>0</Id>
<Name>hello</Name>
<Extra1>boo</Extra1>
<Extra2>good</Extra2>
</Bar1>
</XmlAbstractSerialisationTest.Bar1>
</Foo>
<Foo>
<ParentData>b</ParentData>
<XmlAbstractSerialisationTest.Bar2>
<Bar2>
<Id>0</Id>
<Name>hello</Name>
<Extra1>boo</Extra1>
<Extra2>123</Extra2>
</Bar2>
</XmlAbstractSerialisationTest.Bar2>
</Foo>
</ArrayOfFoo>
上述代码可以序列化和反序列化任意复杂的具体类型,而父类不知道这些类型。 每次处理具体类型时,都需要序列化全名。然后反序列化必须知道全名(编码到元素名称中)和可以找到类型的程序集。
以上代码出现问题! 如果具体类型具有非默认构造函数,则CreateInstance方法将失败。 可能它可以使用FormatterServices.GetUninitializedObject 我明天会玩这个游戏。
此代码应该可以使用,但您需要将“[装配的完整路径]”更新为正确的装配路径。