使用一个类来序列化/反序列化不同的根元素名称

10

我有几个不同根元素但具有相同子元素类型的XML文件,我希望能够创建一个单一的类来保存不同的根元素,并创建另一个用于存储每个子元素的类。 以下是两个XML文件的示例。

文件1:

<?xml version="1.0" encoding="utf-8" ?>
<Sandra>
  <Address>
    <Street></Street>
    <Number></Number>
  </Address>
</Sandra>

文件2:

<?xml version="1.0" encoding="utf-8" ?>
<John>
  <Address>
    <Street></Street>
    <Number></Number>
  </Address>
</John>

我希望只使用2个类就能够序列化和反序列化它,就像这样:

[Serializable]
[XmlRoot]
public class Person
{
    [XmlElement("Address")]
    public List<Address> Adresses { get; set; }
}

[Serializable]
public class Address
{
    public string Street { get; set; }

    public string Number { get; set; }
}

我尝试使用以下方式读取它们:

    var ser = new XmlSerializer(typeof(Person));
    var reader = XmlReader.Create("person1.xml");
    var person = (Person)ser.Deserialize(reader);
但我得到了“XML文档(2,2)中有一个错误”的提示,因为反序列化器期望一个根元素而不是或。如果我将[XmlRoot]更改为[XmlRoot(“John”)],则可以正常工作,但这正是我想要避免的。
另外,我必须能够使用相同的奇怪XML结构将其序列化回来,所以我需要在Person类中存储根元素名称。
我知道我可以简单地创建自己的(反)序列化器,但我想知道是否可以使用现有的方法实现它。
编辑1:(已回滚)。
编辑2:回滚“编辑1”的修改,因为我找到了一种更简单的方法来实现我所需的功能。请参见下面的答案。
4个回答

12

我找到了一种简洁而快速的解决方法! 我只需要在实例化XmlSerializer时使用XmlRootAttribute。这样,我就可以在运行时设置根元素的名称。

var personsName = "Sandra";
var ser = new XmlSerializer(typeof(Person), 
   new XmlRootAttribute { ElementName = personsName });
var reader = XmlReader.Create("person1.xml");
var person = (Person)ser.Deserialize(reader);
当然,如果我想对它进行序列化,它也是同样适用的方式。

3

使用人名作为XML元素名称感觉有些怪异。每个元素代表什么,是一个John还是一个Person

如果您能够控制这些XML文件的格式,那么更好的表示方式可能是这样:

<?xml version="1.0" encoding="utf-8" ?>
<Person name="Sandra">
  <Address>
    <Street></Street>
    <Number></Number>
  </Address>
</Person>

然后,您将有一种简单的方法将名称存储在作为 XML 属性映射的属性中:

[Serializable]
[XmlRoot]
public class Person
{
    [XmlElement("Address")]
    public List<Address> Adresses { get; set; }

    [XmlAttribute("name")]
    public string Name { get; set;}
}

1
是的,确实有点奇怪。但我不能改变XML结构,我只能在读写时尊重这种格式。 - Henrique Miranda

1

在您的类中实现IXmlSerializable,并在以下函数中以您想要的方式进行序列化:

ReadXml(System.Xml.XmlReader reader)WriteXml(System.Xml.XmlWriter writer)

示例:

[Serializable]
public class Threshold : IXmlSerializable
{

public int Type {get;set;}
public object Value {get;set;}
public string Name {get;set;}
public void ReadXml(System.Xml.XmlReader reader)
{


XElement thresholdXML = XElement.Load(reader);

if (!thresholdXML.HasElements || thresholdXML.IsEmpty)
return;

Type = (ThresholdType)int.Parse(thresholdXML.Element("Type").Value);
Value = Type.Equals(ThresholdType.Complex) ? thresholdXML.Element("Value").Value : (object)Decimal.Parse(thresholdXML.Element("Value").Value);
Name = thresholdXML.Element("Name").Value;


}


public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}

public void WriteXml(System.Xml.XmlWriter writer)
{
XmlSerializerNamespaces xmlnsEmpty = new XmlSerializerNamespaces();
xmlnsEmpty.Add("", "");


writer.WriteElementString("Type", ((int)Type).ToString("D"));
writer.WriteElementString("Value", Value.ToString());
writer.WriteElementString("Name", Name);
}
}

我尝试实现'IXmlSerializable', 但是在尝试反序列化第一个存档时,我得到了相同的错误''{"<Sandra xmlns=''> was not expected."}''. 这个类的ReadXml()方法甚至没有被调用。 - Henrique Miranda
首先,您不需要任何[XmlRoot]或[XmlElement]属性。另外,请尝试删除现有的XML并序列化新的XML。在ReadXML()和WriteXML()上设置断点以查看它们是否被调用。跟随调试器并向我更新异常的详细信息以及发生异常的位置。 - sm_
按照您的指示操作后,尝试反序列化时仍然遇到相同的错误:{"<Sandra xmlns=''> was not expected."}。ReadXML 仍未被调用,可能是因为反序列化程序期望类名与根元素名称相同 或者 存在 [XmlRoot("rootname")] 属性。 - Henrique Miranda

0

使用根元素作为ArrayOfClassName,然后尝试它。

<ArrayOfAlarmSummary>
  <AlarmSummary>
    <ClientId>1</ClientId>
    <StationId>2</StationId>
    <StationName>Station-2</StationName>
    <DateTime>13/09/15</DateTime>
    <TagName>AI2_2</TagName>
    <Description>TR DC Current</Description>
    <Units>Amps</Units>
    <NormalOperation>10 to 100</NormalOperation>
    <AlarmValue>132.48</AlarmValue>
    <AlarmDescription>
    </AlarmDescription>
  </AlarmSummary>
  <AlarmSummary>
    <ClientId>1</ClientId>
    <StationId>2</StationId>
    <StationName>Station-2</StationName>
    <DateTime>13/09/15</DateTime>
    <TagName>AI2_2</TagName>
    <Description>TR AC Current</Description>
    <Units>Amps</Units>
    <NormalOperation>10 to 100</NormalOperation>
    <AlarmValue>132.48</AlarmValue>
    <AlarmDescription>
    </AlarmDescription>
  </AlarmSummary>
</ArrayOfAlarmSummary>

这里是反序列化类,使用它您可以反序列化您的XML文件。
 public class SerializeDeserialize<T>
    {
        StringBuilder sbData;
        StringWriter swWriter;
        XmlDocument xDoc;
        XmlNodeReader xNodeReader;
        XmlSerializer xmlSerializer;
        public SerializeDeserialize()
        {
            sbData = new StringBuilder();
        }
        public string SerializeData(T data)
        {
            XmlSerializer employeeSerializer = new XmlSerializer(typeof(T));
            swWriter = new StringWriter(sbData);
            employeeSerializer.Serialize(swWriter, data);
            return sbData.ToString();
        }

        public T DeserializeData(string dataXML)
        {
            xDoc = new XmlDocument();
            xDoc.LoadXml(dataXML);
            xNodeReader = new XmlNodeReader(xDoc.DocumentElement);
            xmlSerializer = new XmlSerializer(typeof(T));
            var employeeData = xmlSerializer.Deserialize(xNodeReader);
            T deserializedEmployee = (T)employeeData;
            return deserializedEmployee;
        }
    }

调用这个类

 var appDomain = System.IO.Directory.GetCurrentDirectory() + "\\AlarmFiles";
            var strPath = Path.Combine(appDomain,
                "Alarm_" + DateTime.Now.ToString("ddMMyyyy") + Constants.FileType.XmlFile);
            var fi = new FileInfo(strPath);
            if (fi.Exists)
            {
                try
                {
                    var xmlString = System.IO.File.ReadAllText(strPath);
                    var serializeAlarmSummary =
                        new SerializeDeserialize<List<AlarmSummary>>();
                    return serializeAlarmSummary.DeserializeData(xmlString);
                }
                catch (Exception ex)
                {
                    throw ex;
                }

            }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接