我有一个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元素
答案 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>;