2009-08-13 37 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> 

这是有点解决办法,但它是最接近你可以得到没有大量的自定义代码。