【问题标题】:.NET serialization of Array to XML. How to set an alias for array type?.NET 将 Array 序列化为 XML。如何为数组类型设置别名?
【发布时间】:2011-04-06 19:48:13
【问题描述】:

我正在尝试将 .net 数组序列化为 XML。这是我想出的一段代码:

    public class Program
    {
        public class Person 
        {
            public string Firstname { get; set; }
            public string Lastname { get; set; }
            public uint Age { get; set; }
        }

        static void Main ()
        {
            Person[] p = 
            {
                new Person{Age = 20, Firstname = "Michael", Lastname = "Jackson"},
                new Person{Age = 21, Firstname = "Bill", Lastname = "Gates"},
                new Person{Age = 22, Firstname = "Steve", Lastname = "Jobs"}
            };

            SerializeObject<Person[]>(p);
        }

        static void SerializeObject<T>(T obj) where T : class
        {
            string fileName = Guid.NewGuid().ToString().Replace("-", "") + ".xml";
            using (FileStream fs = File.Create(fileName)) 
            {
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                ns.Add("", "");
                XmlSerializer ser = new XmlSerializer(typeof(T));
                ser.Serialize(fs, obj, ns);
            }
        }
    }

以下是本示例写入 XML 文件的 XML 内容:

<ArrayOfPerson>
  <Person>
    <Firstname>Michael</Firstname>
    <Lastname>Jackson</Lastname>
    <Age>20</Age>
  </Person>
  <Person>
    <Firstname>Bill</Firstname>
    <Lastname>Gates</Lastname>
    <Age>21</Age>
  </Person>
  <Person>
    <Firstname>Steve</Firstname>
    <Lastname>Jobs</Lastname>
    <Age>22</Age>
  </Person>
</ArrayOfPerson>

但这并不是我真正想要的。我希望它看起来像这样:

<Persons>
  <Person>
    <Firstname>Michael</Firstname>
    <Lastname>Jackson</Lastname>
    <Age>20</Age>
  </Person>
  <Person>
    <Firstname>Bill</Firstname>
    <Lastname>Gates</Lastname>
    <Age>21</Age>
  </Person>
  <Person>
    <Firstname>Steve</Firstname>
    <Lastname>Jobs</Lastname>
    <Age>22</Age>
  </Person>
</Persons>

我怎样才能让它以这种方式工作?提前致谢!

【问题讨论】:

    标签: c# .net xml arrays serialization


    【解决方案1】:

    除了已经提供的建议之外,您只需对代码进行一些小的更改。

    首先需要重新声明 SerializeObject 泛型方法:

    // important: declare the input parameter to be an **array** of T, not T.
    static void SerializeObject<T>(T[] obj) where T : class
    {
        string fileName = Guid.NewGuid().ToString().Replace("-", "") + ".xml";
        using (FileStream fs = File.Create(fileName))
        {
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add("", "");
    
            // override default root node name.  based on your question, 
            // i'm just going to append an "s" to the base type 
            // (e.g., Person becomes Persons)
            var rootName = typeof(T).Name + "s";
            XmlRootAttribute root = new XmlRootAttribute(rootName);
    
            // add the attribute to the serializer constructor...
            XmlSerializer ser = new XmlSerializer(obj.GetType(), root);
    
            ser.Serialize(fs, obj, ns);
        }
    }
    

    其次,在 Main() 方法中,将 SerializeObject&lt;Person[]&gt;(p) 替换为 SerializeObject&lt;Person&gt;(p)。因此,您的 Main() 方法将如下所示:

    static void Main(string[] args)
    {
        Person[] p = 
        {
            new Person{Age = 20, Firstname = "Michael", Lastname = "Jackson"},
            new Person{Age = 21, Firstname = "Bill", Lastname = "Gates"},
            new Person{Age = 22, Firstname = "Steve", Lastname = "Jobs"}
        };
    
        SerializeObject<Person>(p);
    }
    

    生成的 XML 将如下所示:

    <Persons>
      <Person>
        <Firstname>Michael</Firstname>
        <Lastname>Jackson</Lastname>
        <Age>20</Age>
      </Person>
      <Person>
        <Firstname>Bill</Firstname>
        <Lastname>Gates</Lastname>
        <Age>21</Age>
      </Person>
      <Person>
        <Firstname>Steve</Firstname>
        <Lastname>Jobs</Lastname>
        <Age>22</Age>
      </Person>
    </Persons>
    

    要将&lt;Person&gt; 元素名称覆盖为其他名称,请在类上设置XmlType 属性,如下所示:

    [XmlType("personEntry")]
    public class Person
    {
        public string Firstname { get; set; }
        public string Lastname { get; set; }
        public uint Age { get; set; }
    }
    

    生成的 XML 如下所示:

    <Persons>
      <personEntry>
        <Firstname>Michael</Firstname>
        <Lastname>Jackson</Lastname>
        <Age>20</Age>
      </personEntry>
      <personEntry>
        <Firstname>Bill</Firstname>
        <Lastname>Gates</Lastname>
        <Age>21</Age>
      </personEntry>
      <personEntry>
        <Firstname>Steve</Firstname>
        <Lastname>Jobs</Lastname>
        <Age>22</Age>
      </personEntry>
    </Persons>
    

    【讨论】:

    • 好东西!非常感谢!
    • 考虑到这段代码,我可以以某种方式控制数组子节点的名称吗?例如渲染 而不是 ...
    【解决方案2】:

    你需要一个像这样的容器类:

        /// <summary>
        /// Represents an Person collection.
        /// </summary>
        [Serializable]
        [XmlRoot("Persons", IsNullable = false)]
        public sealed class Persons
        {
            /// <summary>
            /// The person collection.
            /// </summary>
            private Collection<Person> persons;
    
            /// <summary>
            /// Initializes a new instance of the <see cref="Persons"/> class.
            /// </summary>
            /// <param name="persons">The person list.</param>
            public Persons(Collection<Person> persons)
            {
                this.persons = persons;
            }
    
            /// <summary>
            /// Initializes a new instance of the <see cref="Persons"/> class.
            /// </summary>
            /// <param name="persons">The person array.</param>
            public Persons(Person[] persons)
                : this(new Collection<Person>(persons))
            {
            }
    
            /// <summary>
            /// Prevents a default instance of the <see cref="Persons"/> class from being created.
            /// </summary>
            private Persons()
            {
            }
    
            /// <summary>
            /// Copies the collection of Person objects to an array and returns
            /// it.
            /// </summary>
            /// <returns>An array of Person objects based on the
            /// collection.</returns>
            public Person[] ToArray()
            {
                Person[] personArray = new Person[this.persons.Count];
    
                this.persons.CopyTo(personArray, 0);
                return personArray;
            }
    
            /// <summary>
            /// Gets or sets the persons.
            /// </summary>
            /// <value>The persons.</value>
            [XmlElement("Person")]
            public Collection<Person> ThePersons
            {
                get
                {
                    return this.persons;
                }
    
                set
                {
                    this.persons = value;
                }
            }
    
            /// <summary>
            /// Gets the length of the persons.
            /// </summary>
            /// <value>The length of the persons.</value>
            [XmlIgnore]
            public int Length
            {
                get
                {
                    return this.persons.Count;
                }
            }
    
            /// <summary>
            /// Returns an enumerator that iterates through the collection.
            /// </summary>
            /// <returns>A <see cref="IEnumerator&lt;Person&gt;"/> that can be used to
            /// iterate through the collection.</returns>
            public IEnumerator<Person> GetEnumerator()
            {
                return (IEnumerator<Person>)this.persons.GetEnumerator();
            }
        }
    

    用你完成的数组初始化它并按照你的Main()方法返回它:

        static void Main ()
        {
            Person[] p = 
            {
                new Person{Age = 20, Firstname = "Michael", Lastname = "Jackson"},
                new Person{Age = 21, Firstname = "Bill", Lastname = "Gates"},
                new Person{Age = 22, Firstname = "Steve", Lastname = "Jobs"}
            };
    
            SerializeObject<Persons>(new Persons(p));
    
            Person[] p2 = DeserializeObject<Persons>("filename.xml").ToArray();
        }
    

    那么反序列化方法就很简单了:

        static T DeserializeObject<T>(string fileName) where T : class
        {
            using (FileStream fs = File.OpenRead(fileName))
            {
                XmlSerializer ser = new XmlSerializer(typeof(T));
                return (T)ser.Deserialize(fs);
            }
        }
    

    选项 2(基于 Nixanswer):

        static void SerializeObject<T>(T obj, Type t) where T : class
        {
            string fileName = Guid.NewGuid().ToString().Replace("-", "") + ".xml";
            using (FileStream fs = File.Create(fileName))
            {
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                ns.Add("", "");
                XmlRootAttribute root = new XmlRootAttribute(t.Name + "s");
                XmlSerializer ser = new XmlSerializer(typeof(T), root);
                ser.Serialize(fs, obj, ns);
            }
        }
    

    可以这样调用:

            SerializeObject<Person[]>(p, typeof(Person));
    

    【讨论】:

    • +1,很好的答案(除了 XML 序列化不需要 [Serializable] 属性)
    • @Thomas:事实如此,谢谢。我从一个正在进行 XML 序列化和远程处理的项目中复制/粘贴。
    • 但现在的问题是......如何将输出 xml 反序列化为 Persons 对象?有什么想法吗?
    • @the_V:我稍微修改了容器类以支持反序列化,并提供了一个快速方法来展示如何反序列化。
    【解决方案3】:

    您可以通过向序列化程序添加根属性来实现。见下文。

     static void SerializeObject<T>(T obj) where T : class
        {
            string fileName = Guid.NewGuid().ToString().Replace("-", "") + ".xml";
            using (FileStream fs = File.Create(fileName)) 
            {
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                ns.Add("", "");
    
                XmlRootAttribute root = new XmlRootAttribute( typeof(T).Name + "s");
    
                XmlSerializer
                  ser = new XmlSerializer(typeof(Person[]), root);
                  ser.Serialize(fs, obj, ns);
            }
        }
    

    或者,您可以传入一个进行名称选择的函数。 你的代码是

     SerializeObject<Person[]>(p, per=>p.GetType().Name);
    
    
    
    static void SerializeObject<T>(T obj, Func<T,string> nameSelector) where T : class
    {
        string fileName = Guid.NewGuid().ToString().Replace("-", "") + ".xml";
        using (FileStream fs = File.Create(fileName))
        {
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add("", "");
    
            XmlRootAttribute root = new XmlRootAttribute(nameSelector(obj));
    
            XmlSerializer
              ser = new XmlSerializer(typeof(Person[]), root);
            ser.Serialize(fs, obj, ns);
        }
    }
    

    【讨论】:

    • 您的解决方案现在仅适用于Persons 情况,不适用于传递给他的SerializeObject 方法的任何其他通用&lt;T&gt;
    • 你可以传入“ArrayName”参数。或者,如果您真的愿意,也可以采用类型并添加一个 S。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 2023-03-08
    • 1970-01-01
    • 2018-01-09
    • 2012-08-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多