Использование сериализатора .NET для сериализации XML в класс .NET - PullRequest
2 голосов
/ 09 ноября 2010

У меня есть 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 ]

2 голосов
/ 09 ноября 2010

Есть быстрый и грязный способ выполнить то, что вы хотите - просто замените "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 голосов
/ 09 ноября 2010

Если вы не хотите создавать класс коллекции для ваших продуктов, вы можете смешать немного 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();
0 голосов
/ 09 ноября 2010

Хотя создание класса не является новым, это экономит вам много кода ... Вам даже не нужно его использовать, за исключением случаев десериализации.

//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);
}
0 голосов
/ 09 ноября 2010

Я не уверен, что вы добьетесь больших успехов, используя сериализатор 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, просто замените метод Parse в XDocument с загрузкой и соответствующую подпись.

0 голосов
/ 09 ноября 2010

Не думаю, что вы можете указать сериализатору выплевывать IList.Сериализатор может создать объект коллекции MyProduct и заполнить его продуктами.Что звучит как то, что вы хотите сделать.

Вы также можете использовать 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});
0 голосов
/ 09 ноября 2010

Проблема в том, что IList не сериализуем, поэтому вам нужно будет реализовать свой собственный XmlSerializer - пройтись по узлам xml и т. Д. Однако вы можете десериализовать свою коллекцию в List, используя готовый XmlSerializer.

Не забудьте добавить конструктор по умолчанию в ваш класс продуктов.

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