2009-08-13 35 views
4

XmlRoot似乎不適用於集合中包含的類。下面是我所定義的類:集合中的Xml序列化

[XmlRoot("cars")] 
public class CarCollection : Collection<Car> 
{ 
} 

[XmlRoot("car")] 
public class Car 
{ 
    [XmlAttribute("make")] 
    public String Make { get; set; } 

    [XmlAttribute("model")] 
    public String Model { get; set; } 
} 

這裏是我使用的序列化這些對象的代碼:

CarCollection cars = new CarCollection(); 
    cars.Add(new Car { Make = "Ford", Model = "Mustang" }); 
    cars.Add(new Car { Make = "Honda", Model = "Accord" }); 
    cars.Add(new Car { Make = "Toyota", Model = "Tundra" }); 

    using (MemoryStream memoryStream = new MemoryStream()) 
    { 
    XmlSerializer carSerializer = new XmlSerializer(typeof(CarCollection)); 
    carSerializer.Serialize(memoryStream, cars); 
    memoryStream.Position = 0; 

    String xml = null; 
    using (StreamReader reader = new StreamReader(memoryStream)) 
    { 
     xml = reader.ReadToEnd(); 
     reader.Close(); 
    } 
    memoryStream.Close(); 
    } 

序列化之後的XML看起來是這樣的:

<cars xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Car make="Ford" model="Mustang" /> 
    <Car make="Honda" model="Accord" /> 
    <Car make="Toyota" model="Tundra" /> 
</cars> 

公告車內的「C」不是小寫字母。爲了做到這一點,我需要改變什麼?如果我直接序列化汽車,它會按我的預期出現。

更新: 我發現了另一個解決方法。我不知道我有多喜歡它,但它適用於我的情況。如果我創建了一個自定義類(請參見下文),並從中派生CarCollection,則序列化將按我的預期工作。

public class XmlSerializableCollection<T> : Collection<T>, IXmlSerializable 
    { 
    public XmlSchema GetSchema() 
    { 
     return null; 
    } 

    public void ReadXml(XmlReader reader) 
    { 
     bool wasEmpty = reader.IsEmptyElement; 
     reader.Read(); 
     if (wasEmpty) 
     { 
     return; 
     } 

     XmlSerializer serializer = new XmlSerializer(typeof(T)); 

     while (reader.NodeType != XmlNodeType.EndElement) 
     { 
     T t = (T)serializer.Deserialize(reader); 
     this.Add(t); 
     } 

     if (reader.NodeType == XmlNodeType.EndElement) 
     { 
     reader.ReadEndElement(); 
     } 
    } 

    public void WriteXml(XmlWriter writer) 
    { 
     XmlSerializer reqSerializer = new XmlSerializer(typeof(T)); 
     foreach (T t in this.Items) 
     { 
     reqSerializer.Serialize(writer, t); 
     } 
    } 
    } 
+0

你知道爲什麼插入自定義XmlSerializableCollection 類的變通辦法導致序列化過程中產生你想要的XML呢? – jameswelle 2009-08-18 21:31:37

+0

它可以工作,因爲我手動序列化子對象,然後尊重子對象上的XMLRoot屬性。 – 2009-08-19 14:04:33

回答

1

難道你不能只用XmlType標記汽車嗎?

[XmlType("car")] 
public class Car 
{ 

} 
1

也許這是一種逃避,但我可以用DataContractSerializer這樣,使這項工作:

using System; 
using System.IO; 
using System.Collections.ObjectModel; 
using System.Runtime.Serialization; 

class Program 
{ 
    static void Main() 
    { 
     CarCollection cars = new CarCollection(); 
     cars.Add(new Car { Make = "Ford", Model = "Mustang" }); 
     cars.Add(new Car { Make = "Honda", Model = "Accord" }); 
     cars.Add(new Car { Make = "Toyota", Model = "Tundra" }); 

     using (MemoryStream memoryStream = new MemoryStream()) 
     { 
      DataContractSerializer serializer 
       = new DataContractSerializer(typeof(CarCollection)); 
      serializer.WriteObject(memoryStream, cars); 
      memoryStream.Position = 0; 

      String xml = null; 
      using (StreamReader reader = new StreamReader(memoryStream)) 
      { 
       xml = reader.ReadToEnd(); 
       reader.Close(); 
      } 
      memoryStream.Close(); 
     } 
    } 
} 

[CollectionDataContract(Name = "cars")] 
public class CarCollection : Collection<Car> { } 

[DataContract(Name = "car")] 
public class Car 
{ 
    [DataMember(Name = "make")] 
    public String Make { get; set; } 

    [DataMember(Name = "model")] 
    public String Model { get; set; } 
} 

輸出:

<cars xmlns="http://schemas.datacontract.org/2004/07/" 
xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> 
    <car> 
    <make>Ford</make> 
    <model>Mustang</model> 
    </car> 
    <car> 
    <make>Honda</make> 
    <model>Accord</model> 
    </car> 
    <car> 
    <make>Toyota</make> 
    <model>Tundra</model> 
    </car> 
</cars> 

注意屬性您的類型已更改爲支持使用DataContractSerializer。我不知道這是否是你想要的方向,但我發現在幾乎所有情況下,我都喜歡使用DataContractSerializer代替較舊的XmlSerializer

+0

這可能會起作用。我只需要讓make和model屬性成爲屬性而不是子節點。 – 2009-08-13 14:31:44

+0

我的錯誤 - 我將編輯修復... – 2009-08-13 14:39:09

2

XmlRootAttribute僅適用於元素是被序列化的對象圖的根,即。您傳遞給XmlSerializer實例的對象。

要控制集合的序列化,您通常會使用XmlElementAttribute來指定用於序列化子對象的元素名稱。不幸的是,該屬性只能應用於字段或屬性而不是類。

如果你能暴露你的集合作爲一個類的屬性,你可以使用屬性如下:

[XmlRoot("cars")] 
public class CarList 
{ 
    [XmlElement("car")] 
    public CarCollection Cars { get; set; } 
} 

與您的代碼示例,將產生以下結果:

<cars xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <car make="Ford" model="Mustang" /> 
    <car make="Honda" model="Accord" /> 
    <car make="Toyota" model="Tundra" /> 
</cars> 

這是有點解決辦法,但它是最接近你可以得到沒有大量的自定義代碼。