2010-11-09 53 views
2

我有一个XML文件:使用.NET序列化XML序列化到.NET类

<?xml version="1.0" encoding="UTF-8"?> 
<MyProducts> 
    <Product Name="P1" /> 
    <Product Name="P2" /> 
</MyProducts> 

和C#对象:

Public Class Product 
{ 
    [XmlAttribute] 
    Public Name {get; set;} 
} 

使用.NET串行类现在我可以将XML文件反序列化为IList而不创建MyProducts对象?

所以我想以某种方式只选择之前我序列

+0

可能重复这个问题:http://stackoverflow.com/questions/226599/deserializing-xml-to-objects-in-c – CodingGorilla 2010-11-09 16:03:07

回答

-1

的问题是,IList的不可序列化,所以你不得不实现自定义XmlSerializer的产品元素 - 通过XML节点等等走,你可以反序列化但使用开箱即用的XmlSerializer将您的收藏集转换为List。

不要忘记添加默认构造函数到您的产品类。

 XmlSerializer serializer = new XmlSerializer(typeof(List<Product>)); 
     FileStream stream = new FileStream(fileName, FileMode.Open); 
     var product = serializer.Deserialize(sream) as List<Product>; 
0

我不认为你可以指示串行器吐出一个IList。序列化器可以创建一个MyProduct集合对象并用Products填充它。这听起来像你想做的事情。

您也可以使用LINQ查询XML文档并创建一个IEnumerable列表。然后

public static IEnumerable<T> DeserializeMany<T>(
    string fileName, string descendentNodeName = null) { 
    descendentNodeName = descendentNodeName ?? typeof(T).Name; 
    var serializer = new XmlSerializer(typeof(T)); 
    return 
    from item in XDocument.Load(fileName).Descendants(descendentNodeName) 
    select (T)serializer.Deserialize(item.CreateReader()); 
} 

,让你列表:

// load from stream if that is the case 
// this just uses a file for demonstration purposes 
XDocument doc = XDocument.Load("location_of_source.xml"); 

// select all Product nodes from the root node and create a new Product object using 
// object initialization syntax 
var listOfProduct = doc.Descendants("Product") 
         .Select(p => new Product { Name = p.Attribute("Name").Value}); 
2

如果您不希望为您的产品的集合类,你可以将某些LINQ与XmlSerializer混合,以XML

var products = XmlSerializerUtils.DeserializeMany<Product>(fileName).ToList(); 
+0

为什么你会在XmlSerializer的混合使用LINQ语句时,LINQ可以自己动手吗? – 2010-11-09 16:22:20

+0

因为,使用LINQ,您必须为每种不同类型的对象创建自定义代码。这也适用于不同的对象。 – 2010-11-09 16:26:26

+0

@Jordao - 您已经创建了自定义代码,在根中查找“Product”节点,并将序列化器的输出转换为Product,所以我没有看到使用序列化器的值。你所做的唯一事情就是让序列化程序为你提供'Product'对象,这并不明显看代码。 – 2010-11-09 16:30:08

2

有一个快速和肮脏的方式来完成你想要的东西 - 只需更换“我的产品”的东西的BCL类是高兴 - ArrayOfProduct

string xml = @"<?xml version='1.0' encoding='UTF-8;'?> 
    <MyProducts> 
     <Product Name='P1' /> 
     <Product Name='P2' /> 
    </MyProducts>"; 
//secret sauce: 
xml = xml.Replace("MyProducts>", "ArrayOfProduct>"); 
IList myProducts; 
using (StringReader sr = new StringReader(xml)) 
{ 
    XmlSerializer xs = new XmlSerializer(typeof(List<Product>)); 
    myProducts = xs.Deserialize(sr) as IList; 
} 
foreach (Product myProduct in myProducts) 
{ 
    Console.Write(myProduct.Name); 
} 

当然,方法是将XML文档适当地更换MyProducts节点 - 而不是使用字符串替换 - 但这说明了这一点。

+0

@anon为什么DV? – 2010-11-09 16:25:47

+1

我没有DV你的答案,但我不喜欢像你一样操纵源XML文档,或者建议有人操纵源XML文档以使其代码工作的想法。 – 2010-11-09 16:31:50

+0

@Dave我认为你误解了答案。将数据从一种格式转换为另一种格式的中间转换非常普遍,正如我在最后所说的,字符串替换是以简单的方式说明这一点。 – 2010-11-09 16:36:05

0

我不确定使用XML序列化器来实现您的需要会取得多大成功。手动解析XML并明确映射它们可能会更简单,例如,

 XDocument xml = XDocument.Parse(@"<?xml version=""1.0"" encoding=""UTF-8""?> 
              <MyProducts> 
               <Product Name=""P1"" /> 
               <Product Name=""P2"" /> 
              </MyProducts>"); 

     foreach(var product in xml.Descendants(XName.Get("Product"))) 
     { 
      var p = new Product { Name = product.Attribute(XName.Get("Name")).Value }; 
      // Manipulate your result and add to your collection. 
     } 

     ... 

     public class Product 
     { 
      public string Name { get; set; } 
     } 

如果您使用的是文件,你最有可能是你的XML,只需更换上的XDocument W /负载和适当的签名Parse方法。

0

虽然不创建类是新颖的,但这样做可以节省大量代码......除了反序列化时,甚至不必使用它。

//Products declaration 
[XmlRoot(ElementName = "MyProducts")] 
public class MyProducts : List<Product> 
{ 
} 

public class Product 
{ 
    [XmlAttribute] 
    public string Name { get; set; } 
} 

... 

[Test] 
public void DeserializeFromString() 
{ 
    var xml = @"<?xml version='1.0' encoding='UTF-8;'?> 
     <MyProducts> 
     <Product Name='P1' /> 
     <Product Name='P2' /> 
     </MyProducts>"; 

    IList<Product> obj = Serialization<MyProducts>.DeserializeFromString(xml); 

    Assert.IsNotNull(obj); 
    Assert.AreEqual(2, obj.Count); 
} 

... 

//Deserialization library 
public static T DeserializeFromString(string serialized) 
{ 
    var byteArray = Encoding.ASCII.GetBytes(serialized); 
    var memStream = new MemoryStream(byteArray); 
    return Deserialize(memStream); 
} 

public static T Deserialize(Stream stream) 
{ 
    var xs = new XmlSerializer(typeof(T)); 
    return (T) xs.Deserialize(stream); 
}