Как использовать XmlSerializer для десериализации простой коллекции в экземпляр List <string> - PullRequest
2 голосов
/ 29 декабря 2010

Мне не удалось найти вопрос, связанный с моей конкретной проблемой.

То, что я пытаюсь сделать, это взять список узлов Xml и напрямую десериализовать их в список без необходимости создавать класс с атрибутами.

Таким образом, xml (myconfig.xml)будет выглядеть примерно так ...

<collection>  
    <item>item1</item>
    <item>item2</item>
    <item>item3</item>
    <item>etc...</item>
</collection>  

В конце я хотел бы получить список элементов в виде строк.

Код будет выглядеть следующим образом.

XmlSerializer serializer = new XmlSerializer( typeof( List<string> ) );
using (XmlReader reader = XmlReader.Create( "myconfig.xml" )
{
    List<string> itemCollection = (List<string>)serializer.Deserialize( reader );
}

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

Ответы [ 3 ]

3 голосов
/ 29 декабря 2010

Вы женаты на идее использования сериализатора? Если нет, вы можете попробовать Linq-to-XML. (.NET 3.5, C # 3 [и выше])

На основе предоставленного вами формата XML-файла это простой код.

// add 'using System.Xml.Linq' to your code file
string file = @"C:\Temp\myconfig.xml";
XDocument document = XDocument.Load(file);
List<string> list = (from item in document.Root.Elements("item")
                     select item.Value)
                    .ToList();
1 голос
/ 12 марта 2014

Чтобы настроить имена элементов списка с помощью XmlSerializer, необходимо обернуть список.

[XmlRoot(Namespace="", ElementName="collection")]
public class ConfigWrapper
{
    [XmlElement("item")]
    public List<string> Items{ get; set;}
}

Использование:

   var itemsList = new List<string>{"item1", "item2", "item3"};
   var cfgIn = new ConfigWrapper{ Items = itemsList };
   var xs = new XmlSerializer(typeof(ConfigWrapper));
   string fileContent = null;

   using (var sw = new StringWriter())
   {
        xs.Serialize(sw, cfgIn);
        fileContent = sw.ToString();
        Console.WriteLine (fileContent);
   }

   ConfigWrapper cfgOut = null;
   using (var sr = new StringReader(fileContent))
   {
        cfgOut = xs.Deserialize(sr) as ConfigWrapper;
        // cfgOut.Dump(); //view in LinqPad
        if(cfgOut != null)
            // yields 'item2'
            Console.WriteLine (cfgOut.Items[1]);
   }

Вывод:

// fileContent:
<?xml version="1.0" encoding="utf-16"?>
<collection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <item>item1</item>
  <item>item2</item>
  <item>item3</item>
</collection>

Еслиесли вы не хотите переносить список, DataContractSerializer позволит вам произвольно назвать элементы, если вы создадите подкласс:

[CollectionDataContract(Name = "collection", ItemName = "item", Namespace = "")]
public class ConfigWrapper : List<string>
{
    public ConfigWrapper() : base() { }
    public ConfigWrapper(IEnumerable<string> items) : base(items) { }
    public ConfigWrapper(int capacity) : base(capacity) { }
}

Использование и вывод:

   var cfgIn = new ConfigWrapper{ "item1", "item2", "item3" };
   var ds = new DataContractSerializer(typeof(ConfigWrapper));
   string fileContent = null;

   using (var ms = new MemoryStream())
   {
        ds.WriteObject(ms, cfgIn);
        fileContent = Encoding.UTF8.GetString(ms.ToArray());
        Console.WriteLine (fileContent);
   }
   // yields: <collection xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><item>item1</item><item>item2</item><item>item3</item></collection>

   ConfigWrapper cfgOut = null;
   using (var sr = new StringReader(fileContent))
   {
        using(var xr = XmlReader.Create(sr))
        {
            cfgOut = ds.ReadObject(xr) as ConfigWrapper;
            // cfgOut.Dump(); //view in LinqPad
            if(cfgOut != null)
                // yields 'item2'
                Console.WriteLine (cfgOut[1]);
        }
   }
1 голос
/ 29 декабря 2010

Хорошо, что интересно, я мог бы найти половину ответа, сериализовав существующий Список.

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

Этот следующий код:

List<string> things = new List<string> { "thing1", "thing2" };
XmlSerializer serializer = new XmlSerializer(typeof(List<string>), overrides);
using (TextWriter textWriter = new StreamWriter("things.xml"))
{
    serializer.Serialize(textWriter, things);
}

Выводит результат:

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <string>thing1</string>
    <string>thing2</string>
</ArrayOfString>

Я могу переопределить корневой узел, передав экземпляр XmlAttributeOverrides второму параметру конструктора XmlSerializer. Он создан так:

XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes attributes = new XmlAttributes { XmlRoot = new XmlRootAttribute("collection") };
overrides.Add( typeof(List<string>), attributes );

Это изменит "ArrayOfString" на "collection". Я до сих пор не понял, как управлять именем строкового элемента.

...