Как десериализовать документ XML в список <>, переопределяя имена элементов - PullRequest
3 голосов
/ 14 июля 2011

Я пытаюсь десериализовать документ XML в список <>.Моя цель состоит в том, чтобы у List <> был публичный статический метод, который возвращает себя заполненный из документа XML.

Вот XML:

<?xml version="1.0"?>
<root>
    <item>
        <name>Blue</name>
    </item>
    <item>
        <name>Red</name>
    </item>
</root>

Вот класс для элемента(BillingItem.cs):

using System;
using System.Xml.Serialization;

namespace DeserializeExample
{
    [Serializable]
    [XmlRoot("item")]
    public class BillingItem
    {
        [XmlElement("name")]
        public string Description { get; set; }
    }
}

Вот класс, который является списком (BillingItems.cs):

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;

namespace DeserializeExample
{
    [Serializable]
    [XmlRoot("root")]
    public class BillingItems : List<BillingItem>
    {
        public static BillingItems GetBillingItems()
        {
            using (TextReader reader = new StreamReader("BillingItems.xml"))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(BillingItems));
                return (BillingItems)serializer.Deserialize(reader);
            }
        }
    }
}

А вот консольное приложение с примером того, как яхотел бы иметь возможность получить список (Program.cs):

namespace DeserializeExample
{
    class Program
    {
        static void Main(string[] args)
        {
            BillingItems billingItems = BillingItems.GetBillingItems();
        }
    }
}

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

Я надеюсь, что пример прост, хорошо объяснен и что кто-то может помочь.

Ответы [ 3 ]

3 голосов
/ 14 июля 2011

Я бы инкапсулировал список - частично для простоты (избегая некоторых грубых перегрузок конструктора XmlSerializer) и частично потому, что здесь есть некоторые глюки в CF и т. Д., Которые делают его ненадежным. Но:

public class BillingItem
{
    [XmlElement("name")]
    public string Description { get; set; }
}
[XmlRoot("root")]
public class MyResult
{
    [XmlElement("item")]
    public List<BillingItem> Items { get; set; }
}

(я удалил все ненужные другие атрибуты)

Затем вы просто возвращаете MyResult (названный более подходящим образом, очевидно), и он будет сериализован в соответствии с вашим примером.

1 голос
/ 14 июля 2011

Из вашего примера похоже, что сериализация не нужна. Если это не так, рассмотрите синтаксический анализ с использованием LINQ-to-XML:

using System.Xml.Linq;

public class BillingItems : List<BillingItem>
{
    // Constructor.
    private BillingItems(List<BillingItem> items) : base(items) { }

    public static BillingItems GetBillingItems()
    {
        var doc = XDocument.Load("BillingItems.xml");
        var items = (from i in doc.Element("root").Elements("item")
                        select new BillingItem { Description = i.Element("name").Value })
                    .ToList();
        return new BillingItems(items);
    }
}

Вы также можете рассмотреть возможность использования IEnumerable <>, а не List <>, если только вы не планируете вставлять / удалять элементы.

РЕДАКТИРОВАТЬ: изменил вышеуказанный код так, чтобы BillingItems наследовал список <>, согласно комментарию ОП ниже.

0 голосов
/ 14 июля 2011

Хорошо, хотя мне это не нравится, потому что я считаю, что в XmlSerializer есть что-то, что сделает это для меня, но, тем временем, я собираюсь сделать следующее.

Добавление инкапсулирующего класса со списком, который я действительно хочу:

using System.Xml.Serialization;

namespace DeserializeExample
{
    [XmlRoot("root")]
    public class BillingItemResult
    {
        [XmlElement("item")]
        public BillingItems Items { get; set; }
    }
}

Затем в моем классе BillItems.cs закрытый статический метод void получит инкапсулирующий объект и вернет его список элементов выставления счетов:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace DeserializeExample
{
    [Serializable]
    [XmlRoot("root")]
    public class BillingItems : List<BillingItem>
    {
        public static BillingItems GetBillingItems()
        {
            using (TextReader reader = new StreamReader("BillingItems.xml"))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(BillingItemResult));
                BillingItemResult billingItemResult = (BillingItemResult)serializer.Deserialize(reader);
                return billingItemResult.Items;
            }
        }
    }
}

Это позволяет сохранить дизайн и условные обозначения существующего приложения. Вот образец из CLI:

using System.Collections.Generic;
namespace DeserializeExample
{
    class Program
    {
        static void Main(string[] args)
        {
            BillingItems billingItems = BillingItems.GetBillingItems();
        }
    }
}

Хотя это работает, я все еще верю, что есть нечто более простое, для которого не требуется дополнительный класс упаковки.

...