С XmlSerializer, как установить имена элементов для списка? - PullRequest
0 голосов
/ 11 июня 2018

Не получается заставить работать атрибуты XmlSerializer.У меня есть

public class DriveData
{
    public string Model { get; set; }
    public string Type { get; set; }
    public int SizeGB { get; set; }
    public string SerialNumber { get; set; }
    public bool IsOK { get; set; }
}
static List<DriveData> DiskDrives { get; set; }
XmlSerializer serializer = new XmlSerializer(typeof(List<DriveData>));
FileStream xmlFile = File.Create("DiskDrives.xml");
serializer.Serialize(xmlFile, DiskDrives);
xmlFile.Close();

Что я хочу:

<?xml version="1.0" encoding="utf-8" ?>
<HardDrives>
    <HardDrive>
        <Model>Seagate1</Model>
        ...
</HardDrive>
<HardDrive>
    ...
</HardDrive>

Но я получаю:

<?xml version="1.0"?>
<ArrayOfDriveData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <DriveData>
    <Model>Seagate1</Model>
    <Type>SATA</Type>
    <SizeGB>999</SizeGB>
    ...
  </DriveData>
  <DriveData>
    ...
  </DriveData>
</ArrayOfDriveData>

[XmlElement(ElementName = "HardDrives")] на моем List<DriveData> ничего не делает.[XmlElement(ElementName = "HardDrive")] в моем классе DriveData вызывает ошибку сборки.Как мне установить имена корневых элементов и элементов <HardDrive> на то, что я хочу?

Ответы [ 3 ]

0 голосов
/ 11 июня 2018

Могут быть и более лучшие способы добиться этого, но есть и другой подход.

private static void GenerateXml()
{
        List<DriveData> DiskDrives = new List<DriveData>();
        DiskDrives.Add(new DriveData() { Model = "model1", Type = "type1", SizeGB = 10, SerialNumber = "20155", IsOK = false });
        DiskDrives.Add(new DriveData() { Model = "model2", Type = "type2", SizeGB = 20, SerialNumber = "20165", IsOK = true });

        var newDoc = new XDocument(new XDeclaration("1.0", null, "yes"));
        XElement xmlElements = new XElement("HardDrives",
            from item in DiskDrives
            select new XElement("HardDrive",
                new XElement("Model", item.Model),
                new XElement("Type", item.Type),
                new XElement("SizeGB", item.SizeGB),
                new XElement("SerialNumber", item.SerialNumber),
                new XElement("IsOK", item.IsOK)));
        newDoc.Add(xmlElements);
        newDoc.Save(@"C:\sample.xml");
}

Выходной XML:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<HardDrives>
  <HardDrive>
    <Model>model1</Model>
    <Type>type1</Type>
    <SizeGB>10</SizeGB>
    <SerialNumber>20155</SerialNumber>
    <IsOK>false</IsOK>
  </HardDrive>
  <HardDrive>
    <Model>model2</Model>
    <Type>type2</Type>
    <SizeGB>20</SizeGB>
    <SerialNumber>20165</SerialNumber>
    <IsOK>true</IsOK>
  </HardDrive>
</HardDrives>
0 голосов
/ 11 июня 2018

Вы можете сохранить свою модель.Используйте атрибут XmlType для класса и второй аргумент в качестве нового XmlRootAttribute ("HardDrives") при создании объекта сериализатора.

[XmlType("HardDrive")]
public class DriveData
{
    public string Model { get; set; }
    public string Type { get; set; }
    public int SizeGB { get; set; }
    public string SerialNumber { get; set; }
    public bool IsOK { get; set; }
}

class Program
{
    static List<DriveData> DiskDrives  { get; set; } = new List<DriveData>();

    static void Main(string[] args)
    {
        DiskDrives.Add(new DriveData { Model = "Seagate1", Type = "SATA", SizeGB = 999 });
        DiskDrives.Add(new DriveData { Model = "Seagate2", Type = "SATA", SizeGB = 777 });

        XmlSerializer serializer = new XmlSerializer(typeof(List<DriveData>), new XmlRootAttribute("HardDrives"));
        FileStream xmlFile = File.Create("DiskDrives.xml");

        serializer.Serialize(xmlFile, DiskDrives);
        xmlFile.Close();

        Console.Read();
    }      
}
0 голосов
/ 11 июня 2018

В то время как XmlSerializer может напрямую сериализовать List<T>, как вы делаете с new XmlSerializer(typeof(List<DriveData>)), компромисс в том, что вы ничего не можете сделать с именами произведенных элементов.Лучший способ - обернуть список в класс, который будет приписываться следующим образом:

[XmlRoot("HardDrives")]
public class DiskDrives
{
    [XmlElement("HardDrive")]
    public List<DriveData> Drives { get; set; }
}

Атрибут [XmlRoot] обозначает элемент документа верхнего уровня, а атрибут [XmlElement] контролирует, как свойствосериализуется.

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

<?xml version="1.0" encoding="utf-16"?>
<HardDrives xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <HardDrive>
    <Model>WD</Model>
    …
  </HardDrive>
  <HardDrive>
    <Model>Seagate</Model>
    …
  </HardDrive>
</HardDrives>

В случае, если вы встраиваете List<DriveData> в более сложную структуру, альтернативныйподход заключается в использовании атрибутов [XmlArray] и [XmlArrayItem], которые управляют тем, как сериализуется свойство IEnumerable и какое имя элемента применяется к его элементам.Следующая структура данных:

[XmlRoot("Inventory")]
public class Inventory
{
    … more properties here…

    [XmlArray("HardDrives")]
    [XmlArrayItem("HardDrive")]
    public List<DriveData> Drives { get; set; }
}

выдаст такой XML-код:

<?xml version="1.0" encoding="utf-16"?>
<Inventory xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  … more properties would be serialized here …
  <HardDrives>
    <HardDrive>
      <Model>WD</Model>
      …
    </HardDrive>
    <HardDrive>
      <Model>Seagate</Model>
      …
    </HardDrive>
  </HardDrives>
</Inventory>
...