嵌套对象的XML序列化,但在根级别

本文关键字:对象 XML 序列化 嵌套 | 更新日期: 2023-09-27 18:21:20

我想序列化一个嵌套对象,使其属性与父对象处于同一级别(即,不在嵌套标记中)。具体来说:我有一个C#对象:

[XmlRoot(ElementName="Root")]
public class TopLevel
{
   public string topLevelProperty;
   public NestedObject nestedObj;
}
public class NestedObject
{
   string propetyOnNestedObject;
}

我想要类似XML的:

<root>
   <topLevelProperty>...</topLevelProperty>
   <propertyOnNestedObject>...</propertyOnNestedObject>
   <!--NOTE: propertyOnNestedObject would normally be inside a "<nested>" tag
       but I'm trying to avoid that here-->
</root> 

这可能吗?

嵌套对象的XML序列化,但在根级别

您需要实现IXmlSerializable接口来覆盖默认行为

[XmlRoot(ElementName = "Root")]
public class TopLevel : IXmlSerializable
{
    public string topLevelProperty;
    public NestedObject nestedObj;
    public XmlSchema GetSchema()
    {
        return null;
    }
    public void ReadXml(XmlReader reader)
    {
        //...
    }
    public void WriteXml(XmlWriter writer)
    {
        writer.WriteElementString("topLevelProperty", topLevelProperty);
        writer.WriteElementString("propertyOnNestedObject", nestedObj.propetyOnNestedObject);
    }
}

CodeProject上还有一篇关于如何正确实现接口的好文章:http://www.codeproject.com/Articles/43237/How-to-Implement-IXmlSerializable-Correctly

作为一种情况,您可以公开嵌套的proeprty访问器,但这会使TopLevel对象稍微复杂一些。因此,作为一个案例,您可以引入一个单独的可序列化包装器,将这种特殊的案例包装器与业务对象本身解耦。

[XmlRoot(ElementName="Root")] 
public class TopLevel 
{    
   public string topLevelProperty;    
   [XmlIgnore]
   public NestedObject nestedObj; 
   [XmlElement("NestedProperty")]
   public string NestedPropertyAccessor
   {
       get
       {
         return nestedObj.NestedProperty;
       }
       // set
   }
} 

或者,如果您需要将可序列化对象与业务模型解耦,则将其分离,这样您就不需要通过专门公开的属性来复杂化业务对象本身,只需符合序列化格式:

public class TopLevelSerializableWrapper
{
    public TopLevelSerializableWrapper(TopLevel businessObject)
    {
    }
    // TODO: expose all proeprties which need to serialized
}

您可以使用YAXLib XML序列化库轻松做到这一点:

//[XmlRoot(ElementName = "Root")]
[YAXSerializeAs("Root")]
public class TopLevel
{
    public string topLevelProperty { get; set; }
    public NestedObject nestedObj { get; set; }
}
public class NestedObject
{
    [YAXElementFor("..")]
    string propetyOnNestedObject { get; set; }
}

请注意YAXElementFor("..")属性如何将序列化的位置指向父元素。(".."看起来像文件系统路径中的父文件夹)。