使用.NET序列化程序将XML序列化为.NET类

时间:2010-11-09 16:01:11

标签: c# .net vb.net xml-serialization

我有一个XML文件:

<?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 Serializer类将XML文件反序列化为IList而不创建MyProducts对象吗?

所以我想在序列化之前以某种方式仅选择Product元素

6 个答案:

答案 0 :(得分:2)

如果您不想为产品创建集合类,可以将一些LINQ to XML与XmlSerializer混合使用:

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

然后,获取你的清单:

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

答案 1 :(得分:2)

有一种快速而又肮脏的方法可以实现您的目标 - 只需将“MyProducts”替换为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节点 - 而不是使用字符串替换 - 但这说明了这一点。

答案 2 :(得分:0)

我认为你不能指示序列化程序吐出IList。序列化程序可以创建MyProduct集合对象并使用Products填充它。这听起来像你想要做的。

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

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

答案 3 :(得分: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的文件,只需替换带有Load的XDocument上的Parse方法和相应的签名。

答案 4 :(得分: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);
}

答案 5 :(得分:-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>;