XML'nin <T> Listesinde serileştirilmesi mümkün müdür?


155

Aşağıdaki XML verildiğinde:

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

Ve aşağıdaki sınıf:

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

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

XmlSerializerXml dosyasının serisini kaldırmak için kullanılabilir List<User>mi? Öyleyse, ne tür ek öznitelikler kullanmam gerekecek veya XmlSerializerörneği oluşturmak için hangi ek parametreleri kullanmam gerekiyor ?

User[]Biraz daha az tercih edilirse bir dizi ( ) kabul edilebilir.

Yanıtlar:


137

Listeyi önemsiz bir şekilde içine alabilirsiniz :

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
Ekstra eleman seviyesinden kaçınmak için [XmlElement ("kullanıcı")] ile güzel bir çözüm. Buna bakarak, bir <user> veya <Items> düğümü (XmlElement özniteliğiniz yoksa) yayınlayacağından emin oldum ve sonra bunun altında <user> düğümleri ekledim. Ama denedim ve olmadı, bu yüzden sorunun tam olarak ne istediğini yayar.
Jon Kragh

Yukarıdaki UserList altında iki listem olsaydı ne olurdu? Metodunuzu denedim ve zaten aynı parametre türleriyle XYZ adlı bir üyeyi tanımladığını söylüyor
Kala J

Bunun neden doğru cevap olarak işaretlendiğini bilmiyorum. Listeyi sarmak için bir sınıf eklemeyi içerir. Soru kesinlikle bundan kaçınmaya çalışıyordu.
DDRider62

1
@ DDRider62 soru "sarmadan" demiyor. Çoğu insan oldukça pragmatiktir ve sadece verileri çıkarmak ister. Bu cevap, .Itemsüye aracılığıyla bunu yapmanızı sağlar .
Marc Gravell

50

Eğer süslemeleri ise Userbulunduğu sınıfı XmlTypeharflere maç için:

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

Sonra XmlRootAttributeüzerine XmlSerializerctor istenilen kök sağlamak ve List <> içine doğrudan okuma izin verebilir:

    // 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);
    }

Kredi: dayanarak cevap itibaren YK1 .


11
Benim görüşüme göre, bu açıkça sorunun cevabıdır. Soru <T> Listesinin serileştirilmesi ile ilgiliydi. Belki de hariç tüm diğer çözümler, listeyi içeren bir sarmalama sınıfını içerir, ki bu kesinlikle gönderilen soru değildir ve sorunun yazarının kaçınmaya çalıştığı görülüyor.
DDRider62

1
Bu yaklaşımla, XmlSerializerciddi bir bellek sızıntısını önlemek için statik olarak önbelleğe alınması ve yeniden kullanılması gerekir, ayrıntılar için StreamReader ve XmlSerializer kullanarak Bellek Sızıntısı'na bakın.
dbc

16

Evet, bir Liste <> serisini serileştirecek ve serisini kaldıracaktır. Emin değilseniz [XmlArray] özelliğini kullandığınızdan emin olun.

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

Bu hem Serialize () hem de Deserialize () ile çalışır.


16

Bence daha iyi bir yol buldum. Sınıflarınıza nitelikler koymak zorunda değilsiniz. Serileştirme ve serileştirme için genel listeyi parametre olarak alan iki yöntem yaptım.

Bir göz atın (benim için işe yarıyor):

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;
    }

Böylece istediğiniz listeyi serileştirebilirsiniz! Her seferinde liste türünü belirtmenize gerek yoktur.

        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
Soruyu cevapladığınız için teşekkürler. Ben List<MyClass>belge öğesi için adlandırılması gerektiğini ekleyebilirim ArrayOfMyClass.
Max Toro

8

Evet, Liste <> öğesinin serisini kaldırır. Bir dizide tutmaya ve bir listede sarmaya / kapsüllemeye gerek yoktur.

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

    public UserHolder()
    {
    }

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

Kodun serileştirilmesi,

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

5

<T> Listesi hakkında emin değilim ancak Diziler kesinlikle yapılabilir. Ve biraz sihir, bir Listeye tekrar ulaşmayı gerçekten kolaylaştırır.

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

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

2
"Holder" sınıfı olmadan yapmak mümkün mü?
Daniel Schaffer

@Daniel, AFAIK, hayır. Bazı somut nesne türlerini serileştirmeli ve serileştirmeyi kaldırmalısınız. XML serileştirmenin yerel olarak toplama sınıflarını serileştirmenin başlangıcı olarak desteklediğine inanmıyorum. Yine de% 100 bilmiyorum.
JaredPar

[XmlElement ("list")] bunun yerine [XmlArray ("list")] olmalıdır. Deserialization benim için .NET
4.5'te

2

Peki ya

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);    

Özellikle fantezi değil ama işe yarayacak.


2
Stackoverflow'a hoş geldiniz!
Gönderi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.