C#xml序列化以两种不同的方式存储一个类 - 可能吗?

时间:2011-09-05 12:04:30

标签: c# xml serialization

是否可以使用C#XmlSerialization API以两种不同的方式存储单个类? 例如

class Test
{
     int group1_attr1;
     int group1_attr2;
     int group2_attr1;
}

我想知道如何将类字段分成两部分(组 - 具有指定的属性),每次调用Serialize来控制将存储哪个部分。例如,如果保存为group1

<?xml version="1.0" encoding="utf-8"?>
<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org  /2001/XMLSchema">
<group1_attr1>0</group1_attr1>
<group1_attr2>0</group1_attr2>
</Test>

如果保存为group2

<?xml version="1.0" encoding="utf-8"?>
<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org  /2001/XMLSchema">
<group2_attr1>0</group2_attr1>
</Test>

有没有办法以“干净”的方式做到这一点?如果不是在xmlserialization中,那么也许在二进制中? 然后我想知道如何将这两个文件合并到单个Test实例中的最佳方法是什么。 (请注意,group1和group2中的字段不重叠)

3 个答案:

答案 0 :(得分:1)

这里的代码演示了如何序列化,但是,反序列化将更加棘手,因为反序列化到现有实例并不简单(参见How to use XmlSerializer to deserialize into an existing instance?)。

public class Test
{
  public int group1_attr1;
  public int group1_attr2;
  public int group2_attr1;
}

class Program
{
  static void Main(string[] args)
  {
     System.Xml.Serialization.XmlAttributes xa = 
        new System.Xml.Serialization.XmlAttributes();
     xa.XmlIgnore = true;
     System.Xml.Serialization.XmlAttributeOverrides xo1 = 
        new System.Xml.Serialization.XmlAttributeOverrides();
     xo1.Add(typeof(Test), "group1_attr1", xa);
     xo1.Add(typeof(Test), "group1_attr2", xa);

     System.Xml.Serialization.XmlAttributeOverrides xo2 = 
        new System.Xml.Serialization.XmlAttributeOverrides();
     xo2.Add(typeof(Test), "group2_attr1", xa);

     System.Xml.Serialization.XmlSerializer xs1 = 
        new System.Xml.Serialization.XmlSerializer(typeof(Test), xo1);
     System.Xml.Serialization.XmlSerializer xs2 = 
        new System.Xml.Serialization.XmlSerializer(typeof(Test), xo2);

     Test t1 = new Test();
     t1.group1_attr1 = 1;
     t1.group1_attr2 = 2;
     t1.group2_attr1 = 3;
     using (System.IO.StringWriter sw = new System.IO.StringWriter())
     {
        xs1.Serialize(sw, t1);
        Console.WriteLine(sw);
     }

     using (System.IO.StringWriter sw = new System.IO.StringWriter())
     {
        xs2.Serialize(sw, t1);
        Console.WriteLine(sw);
     }
  }
}

反序列化可以在反序列化之前合并XML:

     Test t2 = new Test();
     System.Xml.Serialization.XmlSerializer xs3 = new System.Xml.Serialization.XmlSerializer(typeof(Test));
     string mergedXml = MergeSerializedXml(group1, group2);

     using (System.IO.StringReader sr = new System.IO.StringReader(mergedXml))
     {
        t2 = (Test)xs3.Deserialize(sr);
     }
...

  static string MergeSerializedXml(string x1, string x2)
  {
     System.Xml.XmlDocument xd = new System.Xml.XmlDocument();
     xd.LoadXml(x1);
     System.Xml.XmlReaderSettings xrs = new System.Xml.XmlReaderSettings();
     xrs.IgnoreWhitespace = true;
     using (System.Xml.XmlReader xr = System.Xml.XmlReader.Create(new System.IO.StringReader(x2), xrs))
     {
        while (xr.Read() && !xr.IsStartElement())
           ;
        xr.MoveToContent();
        xr.Read();
        System.Xml.XmlNode xn = xd.ChildNodes[1];
        do
        {
           xn.AppendChild(xd.ReadNode(xr));
        } while (xr.NodeType != System.Xml.XmlNodeType.EndElement);
     }
     return xd.OuterXml;
  }

答案 1 :(得分:0)

组合将允许您执行此操作,http://en.wikipedia.org/wiki/Composition_over_inheritance。如果您序列化CompositeGroup1,请将其粘贴到CompositeData的实例中。对CompositeGroup2执行相同操作。正如您所说,使用内置的序列化器无法满足您的要求。序列化数据时,它将始终生成该类型的完整序列化。

class CompositeData
{
  public CompositeGroup1 Group1 { get; set; }
  public CompositeGroup2 Group2 { get; set; }
}

class CompositeGroup1
{
  public int Attr1 { get; set; }
  public int Attr2 { get; set; }
}

class CompositeGroup2
{
  public int Attr1 { get; set; }
}

您还可以考虑让CompositeData实现抽象类,每个分组一个。您可以使用其他一些使用传入类型而不是运行时类型的JSON序列化程序来生成序列化数据。

var json1 = serializer.Serialize<AbstractGroup1>(new CompositeData());
var json2 = serializer.Serialize<AbstractGroup2>(new CompositeData());

然而,将它们重新组合在一起仍然是你的问题。

答案 2 :(得分:0)

你可以进入我的项目Xml Serialization Framework,它将使用接口习语来解决你可能遇到的同样问题

示例:

序列化类实例/对象

class Person
{
    public string Name { get; set; }
}

你可能会声明在元数据驱动的xml运行时序列化中使用的接口:

interface IPersonRoot
{
    string Name { get; set; }
}

[XmlRootSerializer("Body")]
interface IPersonCustomRoot
{
    string Name { get; set; }
}

interface IPersonCustomAttribute
{
    [XmlAttributeRuntimeSerializer("Id")]
    string Name { get; set; }
}

该框架甚至支持使用特定接口/ XML格式部分更新活动实例:

使用IPersonRoot接口进出XML:

        <Person>
            <Name>John Doe</Name>
        </Person>

使用IPersonCustomRoot接口进出XML;

        <Body>
            <Name>John Doe</Name>
        </Body>

使用IPersonCustomAttribute接口进出XML:

        <Person Id="John Doe" />

度过愉快的一天,

干杯;)

Artur M。