XmlSerializer 列表项元素名称

发布于 2024-08-22 06:34:42 字数 2043 浏览 6 评论 0原文

我有一个类 PersonList

[XmlRoot("Persons")]
PersonList : List<Human>

当我将其序列化为 XML 时,默认情况下它会生成如下内容:

<Persons>
  <Human>...</Human>
  <Human>...</Human>
</Persons>

我的问题是需要做什么才能将元素 Human 更改为输出中的 Person?所以输出将是:

<Persons>
  <Person>...</Person>
  <Person>...</Person>
</Persons>

并且,如何将上述 XML 反序列化为 PersonList 类对象?

根据尼克的建议,这是我的测试代码:

[XmlRoot("Persons")]
public class Persons : List<Human>
{

}

[XmlRoot("Person")]
public class Human
{
    public Human()
    {
    }

    public Human(string name)
    {
        Name = name;
    }

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

}

void TestXmlSerialize()
{
    Persons personList = new Persons();
    personList.Add(new Human("John"));
    personList.Add(new Human("Peter"));

    try
    {
        using (StringWriter writer = new StringWriter())
        {
            XmlSerializer serializer = new XmlSerializer(typeof(Persons));
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.OmitXmlDeclaration = true;

            XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
            namespaces.Add(string.Empty, string.Empty);

            XmlWriter xmlWriter = XmlWriter.Create(writer, settings);
            serializer.Serialize(xmlWriter, personList, namespaces);

            Console.Out.WriteLine(writer.ToString());
        }
    }
    catch (Exception e)
    {
        Console.Out.WriteLine( e.ToString());
    }
}

测试代码的输出是:

<Persons>
  <Human>
    <Name>John</Name>
  </Human>
  <Human>
    <Name>Peter</Name>
  </Human>
</Persons>

如输出所示,Human 上的 [XmlRoot("Person")] 不将标签从 Human 更改为 Person

I have a class PersonList

[XmlRoot("Persons")]
PersonList : List<Human>

when I serialize this to XML, by default it will produce something like this:

<Persons>
  <Human>...</Human>
  <Human>...</Human>
</Persons>

My question is what needs to be done in order to change element Human to Person in the output? so the output would be :

<Persons>
  <Person>...</Person>
  <Person>...</Person>
</Persons>

and, how to deserialize the above XML to the PersonList class object?

Per Nick's advice, Here is my testing code:

[XmlRoot("Persons")]
public class Persons : List<Human>
{

}

[XmlRoot("Person")]
public class Human
{
    public Human()
    {
    }

    public Human(string name)
    {
        Name = name;
    }

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

}

void TestXmlSerialize()
{
    Persons personList = new Persons();
    personList.Add(new Human("John"));
    personList.Add(new Human("Peter"));

    try
    {
        using (StringWriter writer = new StringWriter())
        {
            XmlSerializer serializer = new XmlSerializer(typeof(Persons));
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.OmitXmlDeclaration = true;

            XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
            namespaces.Add(string.Empty, string.Empty);

            XmlWriter xmlWriter = XmlWriter.Create(writer, settings);
            serializer.Serialize(xmlWriter, personList, namespaces);

            Console.Out.WriteLine(writer.ToString());
        }
    }
    catch (Exception e)
    {
        Console.Out.WriteLine( e.ToString());
    }
}

The output of the testing code is:

<Persons>
  <Human>
    <Name>John</Name>
  </Human>
  <Human>
    <Name>Peter</Name>
  </Human>
</Persons>

As the output shows, the [XmlRoot("Person")] on Human does not change the tag to Person from Human.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

心病无药医 2024-08-29 06:34:42

使用以下属性标记您的类:

[XmlType("Account")]
[XmlRoot("Account")]

XmlType 属性将导致 OP 中请求的输出。根据文档 :

控制 XmlSerializer 序列化属性目标时生成的 XML 架构

Mark your class with the following attributes:

[XmlType("Account")]
[XmlRoot("Account")]

The XmlType attribute will result in the output requested in the OP. Per the documentation:

Controls the XML schema that is generated when the attribute target is serialized by the XmlSerializer

撕心裂肺的伤痛 2024-08-29 06:34:42

我认为您没有办法控制生成的数组元素的名称。

但是,如果您可以将 Persons 集合包装在另一个类中,那么您将可以使用 XmlArrayAttributeXmlArrayItemAttribute 完全控制生成的输出。

如果您无法创建这个新类,您可以求助于实现IXmlSerialized,但这要复杂得多。

第一种选择的示例如下:

[XmlRoot("Context")]
public class Context
{
    public Context() { this.Persons = new Persons(); }

    [XmlArray("Persons")]
    [XmlArrayItem("Person")]
    public Persons Persons { get; set; }
}

public class Persons : List<Human> { }

public class Human
{
    public Human() { }
    public Human(string name) { Name = name; }
    public string Name { get; set; }
}

class Program
{
    public static void Main(string[] args)
    {
        Context ctx = new Context();
        ctx.Persons.Add(new Human("john"));
        ctx.Persons.Add(new Human("jane"));

        var writer = new StringWriter();
        new XmlSerializer(typeof(Context)).Serialize(writer, ctx);

        Console.WriteLine(writer.ToString());
    }
}

I don't think there is a way for you to control the name of the generated array elements.

If you can however wrap the Persons collection inside another class you will then have complete control over the generated output using XmlArrayAttribute and XmlArrayItemAttribute.

If you cannot create this new class you can resort to implementing IXmlSerializable, but this is much more complex.

An example for the first alternative follows:

[XmlRoot("Context")]
public class Context
{
    public Context() { this.Persons = new Persons(); }

    [XmlArray("Persons")]
    [XmlArrayItem("Person")]
    public Persons Persons { get; set; }
}

public class Persons : List<Human> { }

public class Human
{
    public Human() { }
    public Human(string name) { Name = name; }
    public string Name { get; set; }
}

class Program
{
    public static void Main(string[] args)
    {
        Context ctx = new Context();
        ctx.Persons.Add(new Human("john"));
        ctx.Persons.Add(new Human("jane"));

        var writer = new StringWriter();
        new XmlSerializer(typeof(Context)).Serialize(writer, ctx);

        Console.WriteLine(writer.ToString());
    }
}
还给你自由 2024-08-29 06:34:42

我的序列化器也遇到了同样的问题。上面的答案都没有完全起作用。我发现 Human 类上的 XmlRoot 属性明显被忽略,因为它不是文档的根元素。将列表包装在上下文对象中对我来说不是一个选择,因为我无法更改 XML 架构。解决方案是更改 Persons 类。您可以将通用列表包装在一个对象中并更改其序列化方式,而不是对通用列表进行子类化。请参阅下面的示例代码:

[XmlRoot("Persons")]
public class Persons 
{
    public Persons ()
    {
        People = new List<Human>();
    }

    [XmlElement("Person")]
    public List<Human> People 
    { get; set; }
}

public class Human
{
    public Human()
    {
    }

    public Human(string name)
    {
        Name = name;
    }

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

使用 XmlElement 序列化通用列表意味着它不会像 XmlArray 或子类化那样将包装器元素放在列表周围。它还为您提供了向 Persons 类添加属性的额外选项,这就是我的想法的来源:

如何向 XmlArray 元素添加属性(XML 序列化)?

I had the identical problem with my serializer. None of the answers above worked exactly. I found that the XmlRoot attribute on the Human class is plainly ignored because it isn't the root element of the document. Wrapping the list in a context object wasn't an option for me because I can't change the XML schema. The solution is to change up the Persons class. Instead of subclassing a generic list, you wrap it in an object and change how it is serialized. See the sample code below:

[XmlRoot("Persons")]
public class Persons 
{
    public Persons ()
    {
        People = new List<Human>();
    }

    [XmlElement("Person")]
    public List<Human> People 
    { get; set; }
}

public class Human
{
    public Human()
    {
    }

    public Human(string name)
    {
        Name = name;
    }

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

Serializing your generic list using XmlElement means that it won't put the wrapper element around your list like XmlArray does or like the subclassing does. It also gives you the bonus option of adding attributes to the Persons class, which is where I got the idea from:

How do I add a attribute to a XmlArray element (XML Serialization)?

秋心╮凉 2024-08-29 06:34:42

这是我的测试代码

using System.Collections.Generic;
using System.Xml.Serialization;

namespace TestLoadingMultiXml
{
[XmlRoot(ElementName=@"main")]
public class XmlMain
{
    private XmlDataTest data;

    [XmlElement(ElementName=@"datalist")]
    public XmlDataTest Data
    {
        get { return data; }
        set { data = value; }
    } // public XmlDataTest Data

    public XmlMain()
    {
        data = new XmlDataTest();
    }
}

[XmlRoot(ElementName=@"xmldata")]
public class XmlDataTest
{
    private List<DataDetails> listData;

    [XmlElement(ElementName=@"listdata")]
    public List<DataDetails> Data
    {
        get { return listData; }
        set { listData = value; }
    }

    public XmlDataTest()
    {
        listData = new List<DataDetails>();
        for (int i = 0; i < 10; i++)
        {
            DataDetails d = new DataDetails(string.Format("{0}", i));
            listData.Add(d);
        } // for (int i=0; i < 10; i++)
    } // public XmlDataTest()
} // class XmlDataTest

[XmlRoot(ElementName=@"datadetail")]
public class DataDetails
{
    private string name;

    [XmlAttribute(AttributeName=@"name")]
    public string Name
    {
        get
        {
            return name;
        }
        set { name = value; }
    }

    public DataDetails(string _value)
    {
        this.name = _value;
    } // public DataDetails(string _value)

    public DataDetails()
    {
        this.name = "";
    } // public DataDetails()
} // public class DataDetails
}

和运行程序

using System;
using System.IO;
using System.Windows.Forms;
using System.Xml.Serialization;

namespace TestLoadingMultiXml
{
    public partial class Form1 : Form
    {
    private XmlMain xt;
    private string xname = @"x.xml";

    public Form1()
    {
        InitializeComponent();
        this.FormClosing += new FormClosingEventHandler(Form1_FormClosing);
    }

    void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        XmlSerializer x = new XmlSerializer(typeof(XmlMain));
        FileStream fs = new FileStream(xname, FileMode.Create);
        x.Serialize(fs, xt);
        fs.Close();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        xt = new XmlMain();
        xname = Directory.GetCurrentDirectory() + @"\" + xname;
        if (File.Exists(xname))
        {
            XmlSerializer x = new XmlSerializer(typeof(XmlMain));
            FileStream fs = new FileStream(xname, FileMode.Open);
            xt = (XmlMain)x.Deserialize(fs);
            fs.Close();
        } // if (File.Exists(xname))
    }
}
}

这也是结果

<?xml version="1.0"?>
<main xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <datalist>
    <listdata name="0" />
    <listdata name="1" />
    <listdata name="2" />
    <listdata name="3" />
    <listdata name="4" />
    <listdata name="5" />
    <listdata name="6" />
    <listdata name="7" />
    <listdata name="8" />
    <listdata name="9" />
  </datalist>
</main>

This is mine test code

using System.Collections.Generic;
using System.Xml.Serialization;

namespace TestLoadingMultiXml
{
[XmlRoot(ElementName=@"main")]
public class XmlMain
{
    private XmlDataTest data;

    [XmlElement(ElementName=@"datalist")]
    public XmlDataTest Data
    {
        get { return data; }
        set { data = value; }
    } // public XmlDataTest Data

    public XmlMain()
    {
        data = new XmlDataTest();
    }
}

[XmlRoot(ElementName=@"xmldata")]
public class XmlDataTest
{
    private List<DataDetails> listData;

    [XmlElement(ElementName=@"listdata")]
    public List<DataDetails> Data
    {
        get { return listData; }
        set { listData = value; }
    }

    public XmlDataTest()
    {
        listData = new List<DataDetails>();
        for (int i = 0; i < 10; i++)
        {
            DataDetails d = new DataDetails(string.Format("{0}", i));
            listData.Add(d);
        } // for (int i=0; i < 10; i++)
    } // public XmlDataTest()
} // class XmlDataTest

[XmlRoot(ElementName=@"datadetail")]
public class DataDetails
{
    private string name;

    [XmlAttribute(AttributeName=@"name")]
    public string Name
    {
        get
        {
            return name;
        }
        set { name = value; }
    }

    public DataDetails(string _value)
    {
        this.name = _value;
    } // public DataDetails(string _value)

    public DataDetails()
    {
        this.name = "";
    } // public DataDetails()
} // public class DataDetails
}

and running program

using System;
using System.IO;
using System.Windows.Forms;
using System.Xml.Serialization;

namespace TestLoadingMultiXml
{
    public partial class Form1 : Form
    {
    private XmlMain xt;
    private string xname = @"x.xml";

    public Form1()
    {
        InitializeComponent();
        this.FormClosing += new FormClosingEventHandler(Form1_FormClosing);
    }

    void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        XmlSerializer x = new XmlSerializer(typeof(XmlMain));
        FileStream fs = new FileStream(xname, FileMode.Create);
        x.Serialize(fs, xt);
        fs.Close();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        xt = new XmlMain();
        xname = Directory.GetCurrentDirectory() + @"\" + xname;
        if (File.Exists(xname))
        {
            XmlSerializer x = new XmlSerializer(typeof(XmlMain));
            FileStream fs = new FileStream(xname, FileMode.Open);
            xt = (XmlMain)x.Deserialize(fs);
            fs.Close();
        } // if (File.Exists(xname))
    }
}
}

Also this is the result

<?xml version="1.0"?>
<main xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <datalist>
    <listdata name="0" />
    <listdata name="1" />
    <listdata name="2" />
    <listdata name="3" />
    <listdata name="4" />
    <listdata name="5" />
    <listdata name="6" />
    <listdata name="7" />
    <listdata name="8" />
    <listdata name="9" />
  </datalist>
</main>
属性 2024-08-29 06:34:42

将 Human 上的 XmlRoot 设置为:

[XmlRoot("Person")]

Sidebar:

Persons 可能应该是 People

Set the XmlRoot on Human to:

[XmlRoot("Person")]

Sidebar:

Persons should probably be People

桃气十足 2024-08-29 06:34:42

还有另一种选择。您始终可以在集合(以及任何其他类或结构)中实现 IXmlSerialized,以完全控制项目的写入或读取方式。你们中的许多人已经知道,当然,它通常不是首选,因为您最终可能会手动编写“样板”代码,这实际上应该是使用属性指定的自动逻辑。

对于必须匹配合理模式的集合来说,这是合理的。因为框架在这里有一个硬限制,并且如果正确完成,现有项目类型的序列化代码不必重复;即不要在集合代码中重写项目序列化,只需在 ReadXml/WriteXml 实现中创建/调用子 XmlSerializer。

使用 IXmlSerialized 的后果是它不允许您应用 XmlTypeAttribute(引发运行时错误,告诉您只能使用 XmlRootAttribute)。因此,请改为应用 XmlSchemaProviderAttribute 并返回您在 XmlTypeAttribute 中放入的相同限定名称。旧的 GetSchema 方法无论如何都应该返回 null,因为它只是一个保留方法(根据 MSDN),可能是因为他们忘记包含指定不同名称空间的功能。就我个人而言,我在 XmlSchemaProviderAttribute 中使用相同的“GetSchema”方法名称,因此它在旧占位符 GetSchema 方法旁边显示为完全覆盖。

当然,最好的解决方案是 Microsoft 允许我们将 XmlArrayItemAttribute 应用于集合/列表类并在 XmlSerializer 中使用它。默认情况下,它在集合中使用 XML 类型元素名称,我认为这是一个错误,因为指定时它应该是 XML 根名称,未指定时它应该是类名称。

当我有时间时,我会回来添加一个例子。现在看一下 IXmlSerialized 和 XmlSchemaProviderAttribute 的 MSDN 文档示例。

http://msdn .microsoft.com/en-us/library/system.xml.serialization.ixmlserialized(v=vs.110).aspx

http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlschemaproviderattribute( v=vs.110).aspx

There is another alternative. You can always implement IXmlSerializable in collections (and any other class or struct) to fully control how items are written or read. Many of you will know that already, it's not generally preferred of course as you may end-up writing out "boiler-plate" code by hand which should really be automatic logic specified with attributes.

For collections which must match a sensible schema it's justifiable. Because the framework has a hard limitation here and the existing item type's serialization code does not have to be duplicated when done properly; i.e. Do not re-write the item serialization in the collection code, just create/call a child XmlSerializer inside your ReadXml/WriteXml implementation.

Once consequence of using IXmlSerializable is it does not allow you to apply the XmlTypeAttribute (throws a runtime error telling you only XmlRootAttribute may be used). So instead apply the XmlSchemaProviderAttribute and return the same qualified name you would have put in the XmlTypeAttribute. The old GetSchema method should return null anyway as it was only a reserved method (according to MSDN), probably because they forgot to include the ability to specify a different namespace. Personally I use the same "GetSchema" method name in my XmlSchemaProviderAttribute so it appears as a complete override next to the legacy placeholder GetSchema method.

Of course, the best solution would be if Microsoft would allow us to apply the XmlArrayItemAttribute to collection/list classes and use that in the XmlSerializer. By default it uses the XML type element name in collections, which I feel is a bug because it should be the XML root name when specified or class name when not.

When I get time I'll come back and add an example. For now take a look at the MSDN documentation examples of IXmlSerializable and XmlSchemaProviderAttribute.

http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable(v=vs.110).aspx

http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlschemaproviderattribute(v=vs.110).aspx

街角迷惘 2024-08-29 06:34:42

如果您无权访问 Human 类的源(在这种情况下,无法设置 XmlRoot),则可以创建 XmlElementAttribute,然后将其添加到 XmlAttributeOverride 并在创建 XmlSerializer 实例时使用它。 请参阅这篇 MSDN 文章了解更多详细信息

If you don't have access to the source for the Human class (in which case, setting XmlRoot is not possible), you can create an XmlElementAttribute, then add it to an XmlAttributeOverride and use that when creating an instance of your XmlSerializer. See this MSDN article for more details.

紫﹏色ふ单纯 2024-08-29 06:34:42

我知道这是一个老问题,但我遇到了同样的问题,并且没有一个解决方案似乎可以解决OP的问题。所以这是我的解决方案(如果您想知道,评论是法语):

#region Références
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
#endregion

namespace XmlSerializationTests
{
    /// <summary>
    /// Représente une liste qui peut être sérialisée en XML en tant que noeud racine.
    /// </summary>
    /// <typeparam name="T">Type des éléments de la liste.</typeparam>
    public class XmlSerializableList<T>
        : List<T>, IXmlSerializable
    {
        #region Variables
        private static readonly XmlSerializer _ItemSerializer = new XmlSerializer(typeof(T));
        private static readonly string _ItemName;
        private string _RootName;
        #endregion

        #region Méthodes
        /// <summary>
        /// Initialisation statique
        /// </summary>
        static XmlSerializableList()
        {
            _ItemName = (typeof(T).GetCustomAttributes(typeof(XmlRootAttribute), true).FirstOrDefault() as XmlRootAttribute)?.ElementName ?? typeof(T).Name;
        }

        /// <summary>
        /// Obtient le nom racine.
        /// </summary>
        protected virtual string RootName
        {
            get
            {
                if (string.IsNullOrWhiteSpace(_RootName)) _RootName = (GetType().GetCustomAttributes(typeof(XmlRootAttribute), true).FirstOrDefault() as XmlRootAttribute)?.ElementName ?? GetType().Name;
                return _RootName;
            }
        }

        /// <summary>
        /// Obtient le nom des éléments.
        /// </summary>
        protected virtual string ItemName
        {
            get { return _ItemName; }
        }

        /// <summary>
        /// Cette méthode est réservée et ne doit pas être utilisée.Lorsque vous implémentez l'interface IXmlSerializable, vous devez retourner la valeur null (Nothing dans Visual Basic) à partir cette méthode et, si la spécification d'un schéma personnalisé est requise, appliquez à la place <see cref="T:System.Xml.Serialization.XmlSchemaProviderAttribute"/> à la classe.
        /// </summary>
        /// <returns> <see cref="T:System.Xml.Schema.XmlSchema"/> qui décrit la représentation XML de l'objet qui est généré par la méthode <see cref="M:System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter)"/> et utilisé par la méthode <see cref="M:System.Xml.Serialization.IXmlSerializable.ReadXml(System.Xml.XmlReader)"/>.</returns>
        public XmlSchema GetSchema()
        {
            return null;
        }

        /// <summary>
        /// Génère un objet à partir de sa représentation XML.
        /// </summary>
        /// <param name="reader"><see cref="T:System.Xml.XmlReader"/> source à partir de laquelle l'objet est désérialisé.</param>
        public void ReadXml(XmlReader reader)
        {
            if (!reader.IsEmptyElement)
            {
                reader.ReadStartElement();
                while (reader.NodeType != XmlNodeType.EndElement)
                {
                    T item = (T) _ItemSerializer.Deserialize(reader);
                    Add(item);
                }
                reader.ReadEndElement();
            }
            else reader.ReadStartElement();
        }

        /// <summary>
        /// Convertit un objet en sa représentation XML.
        /// </summary>
        /// <param name="writer"><see cref="T:System.Xml.XmlWriter"/> flux dans lequel l'objet est sérialisé.</param>
        public void WriteXml(XmlWriter writer)
        {
            foreach (var i in this)
            {
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                ns.Add("", "");
                _ItemSerializer.Serialize(writer, i, ns);
            }
        }
        #endregion
    }
}

这里有一个单元测试类来演示使用和结果:

#region Références
using System.IO;
using System.Text;
using System.Xml.Serialization;
using Microsoft.VisualStudio.TestTools.UnitTesting;
#endregion

namespace XmlSerializationTests
{
    [TestClass]
    public class XmlSerializableListTests
    {
        public class Person
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public int Birth { get; set; }
        }

        [XmlRoot("color")]
        public class ColorDefinition
        {
            [XmlElement("name")] public string Name { get; set; }
            [XmlElement("r")] public int Red { get; set; }
            [XmlElement("g")] public int Green { get; set; }
            [XmlElement("b")] public int Blue { get; set; }
        }

        public class Persons : XmlSerializableList<Person>
        {
        }

        [XmlRoot("colors")]
        public class ColorList : XmlSerializableList<ColorDefinition>
        {
        }

        private T ReadXml<T>(string text) where T : class
        {
            XmlSerializer serializer = new XmlSerializer(typeof (T));
            using (StringReader sr = new StringReader(text))
            {
                return serializer.Deserialize(sr) as T;
            }
        }

        private string WriteXml<T>(T data) where T : class
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            StringBuilder sb = new StringBuilder();
            using (StringWriter sw = new StringWriter(sb))
            {
                serializer.Serialize(sw, data);
                return sb.ToString();
            }
        }

        [TestMethod]
        public void ReadEmpty()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<XmlSerializableListOfInt32>
</XmlSerializableListOfInt32>";
            XmlSerializableList<int> lst = ReadXml<XmlSerializableList<int>>(xml);
            Assert.AreEqual(0, lst.Count);
        }

        [TestMethod]
        public void ReadEmpty2()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<XmlSerializableListOfInt32 />";
            XmlSerializableList<int> lst = ReadXml<XmlSerializableList<int>>(xml);
            Assert.AreEqual(0, lst.Count);
        }

        [TestMethod]
        public void ReadSimpleItems()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<XmlSerializableListOfInt32>
  <int>0</int>
  <int>52</int>
  <int>79</int>
</XmlSerializableListOfInt32>";
            XmlSerializableList<int> lst = ReadXml<XmlSerializableList<int>>(xml);
            Assert.AreEqual(3, lst.Count);
            Assert.AreEqual(0, lst[0]);
            Assert.AreEqual(52, lst[1]);
            Assert.AreEqual(79, lst[2]);
        }

        [TestMethod]
        public void ReadComplexItems()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<XmlSerializableListOfPerson>
  <Person>
    <FirstName>Linus</FirstName>
    <LastName>Torvalds</LastName>
    <Birth>1969</Birth>
  </Person>
  <Person>
    <FirstName>Bill</FirstName>
    <LastName>Gates</LastName>
    <Birth>1955</Birth>
  </Person>
  <Person>
    <FirstName>Steve</FirstName>
    <LastName>Jobs</LastName>
    <Birth>1955</Birth>
  </Person>
</XmlSerializableListOfPerson>";
            XmlSerializableList<Person> lst = ReadXml<XmlSerializableList<Person>>(xml);
            Assert.AreEqual(3, lst.Count);
            Assert.AreEqual("Linus", lst[0].FirstName);
            Assert.AreEqual("Torvalds", lst[0].LastName);
            Assert.AreEqual(1969, lst[0].Birth);
            Assert.AreEqual("Bill", lst[1].FirstName);
            Assert.AreEqual("Gates", lst[1].LastName);
            Assert.AreEqual(1955, lst[1].Birth);
            Assert.AreEqual("Steve", lst[2].FirstName);
            Assert.AreEqual("Jobs", lst[2].LastName);
            Assert.AreEqual(1955, lst[2].Birth);
        }

        [TestMethod]
        public void ReadInheritedPersons()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<Persons>
  <Person>
    <FirstName>Linus</FirstName>
    <LastName>Torvalds</LastName>
    <Birth>1969</Birth>
  </Person>
  <Person>
    <FirstName>Bill</FirstName>
    <LastName>Gates</LastName>
    <Birth>1955</Birth>
  </Person>
  <Person>
    <FirstName>Steve</FirstName>
    <LastName>Jobs</LastName>
    <Birth>1955</Birth>
  </Person>
</Persons>";
            Persons lst = ReadXml<Persons>(xml);
            Assert.AreEqual(3, lst.Count);
            Assert.AreEqual("Linus", lst[0].FirstName);
            Assert.AreEqual("Torvalds", lst[0].LastName);
            Assert.AreEqual(1969, lst[0].Birth);
            Assert.AreEqual("Bill", lst[1].FirstName);
            Assert.AreEqual("Gates", lst[1].LastName);
            Assert.AreEqual(1955, lst[1].Birth);
            Assert.AreEqual("Steve", lst[2].FirstName);
            Assert.AreEqual("Jobs", lst[2].LastName);
            Assert.AreEqual(1955, lst[2].Birth);
        }

        [TestMethod]
        public void ReadInheritedColors()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<colors>
  <color>
    <name>red</name>
    <r>255</r>
    <g>0</g>
    <b>0</b>
  </color>
  <color>
    <name>green</name>
    <r>0</r>
    <g>255</g>
    <b>0</b>
  </color>
  <color>
    <name>yellow</name>
    <r>255</r>
    <g>255</g>
    <b>0</b>
  </color>
</colors>";
            ColorList lst = ReadXml<ColorList>(xml);
            Assert.AreEqual(3, lst.Count);
            Assert.AreEqual("red", lst[0].Name);
            Assert.AreEqual(255, lst[0].Red);
            Assert.AreEqual(0, lst[0].Green);
            Assert.AreEqual(0, lst[0].Blue);
            Assert.AreEqual("green", lst[1].Name);
            Assert.AreEqual(0, lst[1].Red);
            Assert.AreEqual(255, lst[1].Green);
            Assert.AreEqual(0, lst[1].Blue);
            Assert.AreEqual("yellow", lst[2].Name);
            Assert.AreEqual(255, lst[2].Red);
            Assert.AreEqual(255, lst[2].Green);
            Assert.AreEqual(0, lst[2].Blue);
        }

        [TestMethod]
        public void WriteEmpty()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<XmlSerializableListOfInt32 />";
            XmlSerializableList<int> lst = new XmlSerializableList<int>();
            string result = WriteXml(lst);
            Assert.AreEqual(xml, result);
        }

        [TestMethod]
        public void WriteSimpleItems()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<XmlSerializableListOfInt32>
  <int>0</int>
  <int>52</int>
  <int>79</int>
</XmlSerializableListOfInt32>";
            XmlSerializableList<int> lst = new XmlSerializableList<int>() {0, 52, 79};
            string result = WriteXml(lst);
            Assert.AreEqual(xml, result);
        }

        [TestMethod]
        public void WriteComplexItems()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<XmlSerializableListOfPerson>
  <Person>
    <FirstName>Linus</FirstName>
    <LastName>Torvalds</LastName>
    <Birth>1969</Birth>
  </Person>
  <Person>
    <FirstName>Bill</FirstName>
    <LastName>Gates</LastName>
    <Birth>1955</Birth>
  </Person>
  <Person>
    <FirstName>Steve</FirstName>
    <LastName>Jobs</LastName>
    <Birth>1955</Birth>
  </Person>
</XmlSerializableListOfPerson>";
            XmlSerializableList<Person> persons = new XmlSerializableList<Person>
            {
                new Person {FirstName = "Linus", LastName = "Torvalds", Birth = 1969},
                new Person {FirstName = "Bill", LastName = "Gates", Birth = 1955},
                new Person {FirstName = "Steve", LastName = "Jobs", Birth = 1955}
            };
            string result = WriteXml(persons);
            Assert.AreEqual(xml, result);
        }

        [TestMethod]
        public void WriteInheritedPersons()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<Persons>
  <Person>
    <FirstName>Linus</FirstName>
    <LastName>Torvalds</LastName>
    <Birth>1969</Birth>
  </Person>
  <Person>
    <FirstName>Bill</FirstName>
    <LastName>Gates</LastName>
    <Birth>1955</Birth>
  </Person>
  <Person>
    <FirstName>Steve</FirstName>
    <LastName>Jobs</LastName>
    <Birth>1955</Birth>
  </Person>
</Persons>";
            Persons lst = new Persons
            {
                new Person {FirstName = "Linus", LastName = "Torvalds", Birth = 1969},
                new Person {FirstName = "Bill", LastName = "Gates", Birth = 1955},
                new Person {FirstName = "Steve", LastName = "Jobs", Birth = 1955}
            };
            string result = WriteXml(lst);
            Assert.AreEqual(xml, result);
        }

        [TestMethod]
        public void WriteInheritedColors()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<colors>
  <color>
    <name>red</name>
    <r>255</r>
    <g>0</g>
    <b>0</b>
  </color>
  <color>
    <name>green</name>
    <r>0</r>
    <g>255</g>
    <b>0</b>
  </color>
  <color>
    <name>yellow</name>
    <r>255</r>
    <g>255</g>
    <b>0</b>
  </color>
</colors>";
            ColorList lst = new ColorList
            {
                new ColorDefinition { Name = "red", Red = 255, Green = 0, Blue = 0 },
                new ColorDefinition { Name = "green", Red = 0, Green = 255, Blue = 0 },
                new ColorDefinition { Name = "yellow", Red = 255, Green = 255, Blue = 0 }
            };
            string result = WriteXml(lst);
            Assert.AreEqual(xml, result);
        }
    }
}

I know it's an old question but I ran into the same problem and none of the solutions seems to adresse the OP's question. So here is my solution (comments are in french if you wonder) :

#region Références
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
#endregion

namespace XmlSerializationTests
{
    /// <summary>
    /// Représente une liste qui peut être sérialisée en XML en tant que noeud racine.
    /// </summary>
    /// <typeparam name="T">Type des éléments de la liste.</typeparam>
    public class XmlSerializableList<T>
        : List<T>, IXmlSerializable
    {
        #region Variables
        private static readonly XmlSerializer _ItemSerializer = new XmlSerializer(typeof(T));
        private static readonly string _ItemName;
        private string _RootName;
        #endregion

        #region Méthodes
        /// <summary>
        /// Initialisation statique
        /// </summary>
        static XmlSerializableList()
        {
            _ItemName = (typeof(T).GetCustomAttributes(typeof(XmlRootAttribute), true).FirstOrDefault() as XmlRootAttribute)?.ElementName ?? typeof(T).Name;
        }

        /// <summary>
        /// Obtient le nom racine.
        /// </summary>
        protected virtual string RootName
        {
            get
            {
                if (string.IsNullOrWhiteSpace(_RootName)) _RootName = (GetType().GetCustomAttributes(typeof(XmlRootAttribute), true).FirstOrDefault() as XmlRootAttribute)?.ElementName ?? GetType().Name;
                return _RootName;
            }
        }

        /// <summary>
        /// Obtient le nom des éléments.
        /// </summary>
        protected virtual string ItemName
        {
            get { return _ItemName; }
        }

        /// <summary>
        /// Cette méthode est réservée et ne doit pas être utilisée.Lorsque vous implémentez l'interface IXmlSerializable, vous devez retourner la valeur null (Nothing dans Visual Basic) à partir cette méthode et, si la spécification d'un schéma personnalisé est requise, appliquez à la place <see cref="T:System.Xml.Serialization.XmlSchemaProviderAttribute"/> à la classe.
        /// </summary>
        /// <returns> <see cref="T:System.Xml.Schema.XmlSchema"/> qui décrit la représentation XML de l'objet qui est généré par la méthode <see cref="M:System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter)"/> et utilisé par la méthode <see cref="M:System.Xml.Serialization.IXmlSerializable.ReadXml(System.Xml.XmlReader)"/>.</returns>
        public XmlSchema GetSchema()
        {
            return null;
        }

        /// <summary>
        /// Génère un objet à partir de sa représentation XML.
        /// </summary>
        /// <param name="reader"><see cref="T:System.Xml.XmlReader"/> source à partir de laquelle l'objet est désérialisé.</param>
        public void ReadXml(XmlReader reader)
        {
            if (!reader.IsEmptyElement)
            {
                reader.ReadStartElement();
                while (reader.NodeType != XmlNodeType.EndElement)
                {
                    T item = (T) _ItemSerializer.Deserialize(reader);
                    Add(item);
                }
                reader.ReadEndElement();
            }
            else reader.ReadStartElement();
        }

        /// <summary>
        /// Convertit un objet en sa représentation XML.
        /// </summary>
        /// <param name="writer"><see cref="T:System.Xml.XmlWriter"/> flux dans lequel l'objet est sérialisé.</param>
        public void WriteXml(XmlWriter writer)
        {
            foreach (var i in this)
            {
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                ns.Add("", "");
                _ItemSerializer.Serialize(writer, i, ns);
            }
        }
        #endregion
    }
}

And here a unit test class to demonstrate use and results :

#region Références
using System.IO;
using System.Text;
using System.Xml.Serialization;
using Microsoft.VisualStudio.TestTools.UnitTesting;
#endregion

namespace XmlSerializationTests
{
    [TestClass]
    public class XmlSerializableListTests
    {
        public class Person
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public int Birth { get; set; }
        }

        [XmlRoot("color")]
        public class ColorDefinition
        {
            [XmlElement("name")] public string Name { get; set; }
            [XmlElement("r")] public int Red { get; set; }
            [XmlElement("g")] public int Green { get; set; }
            [XmlElement("b")] public int Blue { get; set; }
        }

        public class Persons : XmlSerializableList<Person>
        {
        }

        [XmlRoot("colors")]
        public class ColorList : XmlSerializableList<ColorDefinition>
        {
        }

        private T ReadXml<T>(string text) where T : class
        {
            XmlSerializer serializer = new XmlSerializer(typeof (T));
            using (StringReader sr = new StringReader(text))
            {
                return serializer.Deserialize(sr) as T;
            }
        }

        private string WriteXml<T>(T data) where T : class
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            StringBuilder sb = new StringBuilder();
            using (StringWriter sw = new StringWriter(sb))
            {
                serializer.Serialize(sw, data);
                return sb.ToString();
            }
        }

        [TestMethod]
        public void ReadEmpty()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<XmlSerializableListOfInt32>
</XmlSerializableListOfInt32>";
            XmlSerializableList<int> lst = ReadXml<XmlSerializableList<int>>(xml);
            Assert.AreEqual(0, lst.Count);
        }

        [TestMethod]
        public void ReadEmpty2()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<XmlSerializableListOfInt32 />";
            XmlSerializableList<int> lst = ReadXml<XmlSerializableList<int>>(xml);
            Assert.AreEqual(0, lst.Count);
        }

        [TestMethod]
        public void ReadSimpleItems()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<XmlSerializableListOfInt32>
  <int>0</int>
  <int>52</int>
  <int>79</int>
</XmlSerializableListOfInt32>";
            XmlSerializableList<int> lst = ReadXml<XmlSerializableList<int>>(xml);
            Assert.AreEqual(3, lst.Count);
            Assert.AreEqual(0, lst[0]);
            Assert.AreEqual(52, lst[1]);
            Assert.AreEqual(79, lst[2]);
        }

        [TestMethod]
        public void ReadComplexItems()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<XmlSerializableListOfPerson>
  <Person>
    <FirstName>Linus</FirstName>
    <LastName>Torvalds</LastName>
    <Birth>1969</Birth>
  </Person>
  <Person>
    <FirstName>Bill</FirstName>
    <LastName>Gates</LastName>
    <Birth>1955</Birth>
  </Person>
  <Person>
    <FirstName>Steve</FirstName>
    <LastName>Jobs</LastName>
    <Birth>1955</Birth>
  </Person>
</XmlSerializableListOfPerson>";
            XmlSerializableList<Person> lst = ReadXml<XmlSerializableList<Person>>(xml);
            Assert.AreEqual(3, lst.Count);
            Assert.AreEqual("Linus", lst[0].FirstName);
            Assert.AreEqual("Torvalds", lst[0].LastName);
            Assert.AreEqual(1969, lst[0].Birth);
            Assert.AreEqual("Bill", lst[1].FirstName);
            Assert.AreEqual("Gates", lst[1].LastName);
            Assert.AreEqual(1955, lst[1].Birth);
            Assert.AreEqual("Steve", lst[2].FirstName);
            Assert.AreEqual("Jobs", lst[2].LastName);
            Assert.AreEqual(1955, lst[2].Birth);
        }

        [TestMethod]
        public void ReadInheritedPersons()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<Persons>
  <Person>
    <FirstName>Linus</FirstName>
    <LastName>Torvalds</LastName>
    <Birth>1969</Birth>
  </Person>
  <Person>
    <FirstName>Bill</FirstName>
    <LastName>Gates</LastName>
    <Birth>1955</Birth>
  </Person>
  <Person>
    <FirstName>Steve</FirstName>
    <LastName>Jobs</LastName>
    <Birth>1955</Birth>
  </Person>
</Persons>";
            Persons lst = ReadXml<Persons>(xml);
            Assert.AreEqual(3, lst.Count);
            Assert.AreEqual("Linus", lst[0].FirstName);
            Assert.AreEqual("Torvalds", lst[0].LastName);
            Assert.AreEqual(1969, lst[0].Birth);
            Assert.AreEqual("Bill", lst[1].FirstName);
            Assert.AreEqual("Gates", lst[1].LastName);
            Assert.AreEqual(1955, lst[1].Birth);
            Assert.AreEqual("Steve", lst[2].FirstName);
            Assert.AreEqual("Jobs", lst[2].LastName);
            Assert.AreEqual(1955, lst[2].Birth);
        }

        [TestMethod]
        public void ReadInheritedColors()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<colors>
  <color>
    <name>red</name>
    <r>255</r>
    <g>0</g>
    <b>0</b>
  </color>
  <color>
    <name>green</name>
    <r>0</r>
    <g>255</g>
    <b>0</b>
  </color>
  <color>
    <name>yellow</name>
    <r>255</r>
    <g>255</g>
    <b>0</b>
  </color>
</colors>";
            ColorList lst = ReadXml<ColorList>(xml);
            Assert.AreEqual(3, lst.Count);
            Assert.AreEqual("red", lst[0].Name);
            Assert.AreEqual(255, lst[0].Red);
            Assert.AreEqual(0, lst[0].Green);
            Assert.AreEqual(0, lst[0].Blue);
            Assert.AreEqual("green", lst[1].Name);
            Assert.AreEqual(0, lst[1].Red);
            Assert.AreEqual(255, lst[1].Green);
            Assert.AreEqual(0, lst[1].Blue);
            Assert.AreEqual("yellow", lst[2].Name);
            Assert.AreEqual(255, lst[2].Red);
            Assert.AreEqual(255, lst[2].Green);
            Assert.AreEqual(0, lst[2].Blue);
        }

        [TestMethod]
        public void WriteEmpty()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<XmlSerializableListOfInt32 />";
            XmlSerializableList<int> lst = new XmlSerializableList<int>();
            string result = WriteXml(lst);
            Assert.AreEqual(xml, result);
        }

        [TestMethod]
        public void WriteSimpleItems()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<XmlSerializableListOfInt32>
  <int>0</int>
  <int>52</int>
  <int>79</int>
</XmlSerializableListOfInt32>";
            XmlSerializableList<int> lst = new XmlSerializableList<int>() {0, 52, 79};
            string result = WriteXml(lst);
            Assert.AreEqual(xml, result);
        }

        [TestMethod]
        public void WriteComplexItems()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<XmlSerializableListOfPerson>
  <Person>
    <FirstName>Linus</FirstName>
    <LastName>Torvalds</LastName>
    <Birth>1969</Birth>
  </Person>
  <Person>
    <FirstName>Bill</FirstName>
    <LastName>Gates</LastName>
    <Birth>1955</Birth>
  </Person>
  <Person>
    <FirstName>Steve</FirstName>
    <LastName>Jobs</LastName>
    <Birth>1955</Birth>
  </Person>
</XmlSerializableListOfPerson>";
            XmlSerializableList<Person> persons = new XmlSerializableList<Person>
            {
                new Person {FirstName = "Linus", LastName = "Torvalds", Birth = 1969},
                new Person {FirstName = "Bill", LastName = "Gates", Birth = 1955},
                new Person {FirstName = "Steve", LastName = "Jobs", Birth = 1955}
            };
            string result = WriteXml(persons);
            Assert.AreEqual(xml, result);
        }

        [TestMethod]
        public void WriteInheritedPersons()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<Persons>
  <Person>
    <FirstName>Linus</FirstName>
    <LastName>Torvalds</LastName>
    <Birth>1969</Birth>
  </Person>
  <Person>
    <FirstName>Bill</FirstName>
    <LastName>Gates</LastName>
    <Birth>1955</Birth>
  </Person>
  <Person>
    <FirstName>Steve</FirstName>
    <LastName>Jobs</LastName>
    <Birth>1955</Birth>
  </Person>
</Persons>";
            Persons lst = new Persons
            {
                new Person {FirstName = "Linus", LastName = "Torvalds", Birth = 1969},
                new Person {FirstName = "Bill", LastName = "Gates", Birth = 1955},
                new Person {FirstName = "Steve", LastName = "Jobs", Birth = 1955}
            };
            string result = WriteXml(lst);
            Assert.AreEqual(xml, result);
        }

        [TestMethod]
        public void WriteInheritedColors()
        {
            string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<colors>
  <color>
    <name>red</name>
    <r>255</r>
    <g>0</g>
    <b>0</b>
  </color>
  <color>
    <name>green</name>
    <r>0</r>
    <g>255</g>
    <b>0</b>
  </color>
  <color>
    <name>yellow</name>
    <r>255</r>
    <g>255</g>
    <b>0</b>
  </color>
</colors>";
            ColorList lst = new ColorList
            {
                new ColorDefinition { Name = "red", Red = 255, Green = 0, Blue = 0 },
                new ColorDefinition { Name = "green", Red = 0, Green = 255, Blue = 0 },
                new ColorDefinition { Name = "yellow", Red = 255, Green = 255, Blue = 0 }
            };
            string result = WriteXml(lst);
            Assert.AreEqual(xml, result);
        }
    }
}
冧九 2024-08-29 06:34:42

我知道它已经过时了,但对于其他人来说 -

class Human 之前,添加 [XmlType("Person")] 而不是 [XmlRoot("Person") ]

I know it's old but for others that will come -

Before class Human, add [XmlType("Person")] instead of [XmlRoot("Person")]

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文