เป็นไปได้หรือไม่ที่จะทำการดีซีเรียลไลซ์ XML ไปยังรายการ <T>


155

รับ XML ต่อไปนี้:

<?xml version="1.0"?>
<user_list>
   <user>
      <id>1</id>
      <name>Joe</name>
   </user>
   <user>
      <id>2</id>
      <name>John</name>
   </user>
</user_list>

และชั้นเรียนต่อไปนี้:

public class User {
   [XmlElement("id")]
   public Int32 Id { get; set; }

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

เป็นไปได้ไหมที่จะใช้XmlSerializerdeserialize xml เป็น a List<User>? ถ้าเป็นเช่นนั้นฉันต้องใช้แอตทริบิวต์เพิ่มเติมประเภทใดหรือฉันต้องใช้พารามิเตอร์เพิ่มเติมใดเพื่อสร้างXmlSerializerอินสแตนซ์

อาเรย์ ( User[]) จะยอมรับได้หากเลือกน้อยกว่า

คำตอบ:


137

คุณสามารถแค็ปซูลรายการเล็กน้อย:

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

[XmlRoot("user_list")]
public class UserList
{
    public UserList() {Items = new List<User>();}
    [XmlElement("user")]
    public List<User> Items {get;set;}
}
public class User
{
    [XmlElement("id")]
    public Int32 Id { get; set; }

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

static class Program
{
    static void Main()
    {
        XmlSerializer ser= new XmlSerializer(typeof(UserList));
        UserList list = new UserList();
        list.Items.Add(new User { Id = 1, Name = "abc"});
        list.Items.Add(new User { Id = 2, Name = "def"});
        list.Items.Add(new User { Id = 3, Name = "ghi"});
        ser.Serialize(Console.Out, list);
    }
}

5
ทางออกที่ดีกับ [XmlElement ("ผู้ใช้")] เพื่อหลีกเลี่ยงองค์ประกอบระดับพิเศษ เมื่อมองถึงสิ่งนี้ฉันคิดว่ามันจะปล่อยโหนด <user> หรือ <Items> (ถ้าคุณไม่มีแอตทริบิวต์ XmlElement) จากนั้นเพิ่มโหนด <user> ใต้นั้น แต่ฉันลองแล้วก็ไม่ได้ดังนั้นจึงเปล่งออกมาอย่างที่ต้องการ
Jon Kragh

จะเกิดอะไรขึ้นถ้าฉันมีสองรายการในรายการผู้ใช้ด้านบน ฉันลองใช้วิธีการของคุณแล้วและมันบอกว่ามันได้กำหนดสมาชิกชื่อ XYZ ด้วยพารามิเตอร์ชนิดเดียวกันอยู่แล้ว
Kala J

ฉันไม่รู้ว่าทำไมนี่ถูกทำเครื่องหมายเป็นคำตอบที่ถูกต้อง มันรวมถึงการเพิ่มชั้นเรียนเพื่อห่อรายการ นั่นคือสิ่งที่คำถามพยายามหลีกเลี่ยง
DDRider62

1
@ DDRider62 คำถามไม่ได้พูดว่า "ไม่ห่อ" คนส่วนใหญ่ค่อนข้างใช้งานได้จริงและต้องการรับข้อมูลออกมา คำตอบนี้ช่วยให้คุณทำเช่นนั้นผ่านทาง.Itemsสมาชิก
Marc Gravell

50

หากคุณตกแต่งUserชั้นเรียนด้วยXmlTypeเพื่อให้ตรงกับตัวพิมพ์ใหญ่ที่ต้องการ:

[XmlType("user")]
public class User
{
   ...
}

จากนั้นXmlRootAttributeบนXmlSerializerctor สามารถจัดเตรียมรูตที่ต้องการและอนุญาตให้อ่านโดยตรงใน List <>:

    // e.g. my test to create a file
    using (var writer = new FileStream("users.xml", FileMode.Create))
    {
        XmlSerializer ser = new XmlSerializer(typeof(List<User>),  
            new XmlRootAttribute("user_list"));
        List<User> list = new List<User>();
        list.Add(new User { Id = 1, Name = "Joe" });
        list.Add(new User { Id = 2, Name = "John" });
        list.Add(new User { Id = 3, Name = "June" });
        ser.Serialize(writer, list);
    }

...

    // read file
    List<User> users;
    using (var reader = new StreamReader("users.xml"))
    {
        XmlSerializer deserializer = new XmlSerializer(typeof(List<User>),  
            new XmlRootAttribute("user_list"));
        users = (List<User>)deserializer.Deserialize(reader);
    }

เครดิต: ขึ้นอยู่กับคำตอบจากYK1


11
ในมุมมองของฉันนี้ชัดเจนคำตอบของคำถาม คำถามเกี่ยวกับการยกเลิกการเรียงลำดับในรายการ <T> โซลูชันอื่นทั้งหมดยกเว้นคลาสสิกอาจมีคลาสการตัดเพื่อให้มีรายการซึ่งไม่ใช่คำถามที่โพสต์และแน่นอนว่าผู้เขียนคำถามนั้นพยายามหลีกเลี่ยงสิ่งใด
DDRider62

1
ด้วยวิธีการนี้XmlSerializerจะต้องถูกแคชแบบคงที่และนำกลับมาใช้ใหม่เพื่อหลีกเลี่ยงการรั่วไหลของหน่วยความจำที่รุนแรงดูMemory Leak โดยใช้ StreamReader และ XmlSerializerสำหรับรายละเอียด
dbc

16

ใช่มันจะทำให้เป็นอนุกรมและยกเลิกการเรียงลำดับรายการ <> เพียงให้แน่ใจว่าคุณใช้แอตทริบิวต์ [XmlArray] หากมีข้อสงสัย

[Serializable]
public class A
{
    [XmlArray]
    public List<string> strings;
}

สิ่งนี้ใช้ได้กับทั้ง Serialize () และ Deserialize ()


16

ฉันคิดว่าฉันได้พบวิธีที่ดีกว่า คุณไม่ต้องใส่คุณสมบัติเข้าไปในคลาสของคุณ ฉันได้ทำสองวิธีสำหรับการเป็นอันดับและ deserialization ซึ่งใช้รายการทั่วไปเป็นพารามิเตอร์

ลองดู (เหมาะกับฉัน):

private void SerializeParams<T>(XDocument doc, List<T> paramList)
    {
        System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(paramList.GetType());

        System.Xml.XmlWriter writer = doc.CreateWriter();

        serializer.Serialize(writer, paramList);

        writer.Close();           
    }

private List<T> DeserializeParams<T>(XDocument doc)
    {
        System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(List<T>));

        System.Xml.XmlReader reader = doc.CreateReader();

        List<T> result = (List<T>)serializer.Deserialize(reader);
        reader.Close();

        return result;
    }

ดังนั้นคุณสามารถเรียงลำดับรายการที่คุณต้องการ! คุณไม่จำเป็นต้องระบุประเภทรายการทุกครั้ง

        List<AssemblyBO> list = new List<AssemblyBO>();
        list.Add(new AssemblyBO());
        list.Add(new AssemblyBO() { DisplayName = "Try", Identifier = "243242" });
        XDocument doc = new XDocument();
        SerializeParams<T>(doc, list);
        List<AssemblyBO> newList = DeserializeParams<AssemblyBO>(doc);

3
ขอบคุณที่ตอบคำถาม ฉันจะเพิ่มว่าสำหรับองค์ประกอบเอกสารที่ควรจะตั้งชื่อList<MyClass> ArrayOfMyClass
Max Toro

8

ใช่เป็น deserialize ในรายการ <> ไม่จำเป็นต้องเก็บไว้ในอาร์เรย์และห่อ / ห่อหุ้มในรายการ

public class UserHolder
{
    private List<User> users = null;

    public UserHolder()
    {
    }

    [XmlElement("user")]
    public List<User> Users
    {
        get { return users; }
        set { users = value; }
    }
}

รหัสดีซีเรียลไลซ์

XmlSerializer xs = new XmlSerializer(typeof(UserHolder));
UserHolder uh = (UserHolder)xs.Deserialize(new StringReader(str));

5

ไม่แน่ใจเกี่ยวกับรายการ <T> แต่อาร์เรย์สามารถทำได้อย่างแน่นอน และเวทมนตร์เล็กน้อยทำให้ง่ายต่อการได้รับรายชื่ออีกครั้ง

public class UserHolder {
   [XmlElement("list")]
   public User[] Users { get; set; }

   [XmlIgnore]
   public List<User> UserList { get { return new List<User>(Users); } }
}

2
เป็นไปได้ไหมถ้าไม่มีคลาส "ผู้ถือ"?
Daniel Schaffer

@Daniel, AFAIK, หมายเลข คุณต้องทำให้เป็นอันดับและ deserialize เป็นวัตถุประเภทคอนกรีต ฉันไม่เชื่อว่าการทำให้เป็นอันดับ XML นั้นจะสนับสนุนคลาสการรวบรวมเป็นตัวเริ่มต้นของการทำให้เป็นอนุกรม ฉันไม่ทราบ 100% ว่า
JaredPar

[XmlElement ("list")] ควรเป็น [XmlArray ("list")] แทน นั่นเป็นวิธีเดียวที่ Deserialization ใช้ได้สำหรับฉันใน. NET 4.5
eduardobr

2

เกี่ยวกับ

XmlSerializer xs = new XmlSerializer(typeof(user[]));
using (Stream ins = File.Open(@"c:\some.xml", FileMode.Open))
foreach (user o in (user[])xs.Deserialize(ins))
   userList.Add(o);    

ไม่แฟนซีโดยเฉพาะ แต่ควรทำงาน


2
ยินดีต้อนรับสู่ stackoverflow! จะเป็นการดีกว่าที่จะให้คำอธิบายสั้น ๆ สำหรับโค้ดตัวอย่างเพื่อปรับปรุงความถูกต้องของการโพสต์ :)
Picrofo Software
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.