Запрос десериализованных объектов

#c# #linq #xml-deserialization

#c# #linq #xml-десериализация

Вопрос:

Наличие этого XML, содержащего коллекцию car:

 <?xml version="1.0" encoding="utf-8"?>
<CarCollection>
    <Cars>
        <Car>
            <StockNumber>1020</StockNumber>
            <Make>Nissan</Make>
            <Model>Sentra</Model>
        </Car>
        <Car>
            <StockNumber>1010</StockNumber>
            <Make>Toyota</Make>
            <Model>Corolla</Model>
        </Car>
        <Car>
            <StockNumber>1111</StockNumber>
            <Make>Honda</Make>
            <Model>Accord</Model>
        </Car>
        <Car>
            <StockNumber>2000</StockNumber>
            <Make>Maybach</Make>
            <Model>S 600</Model>
        </Car>
        <Car>
            <StockNumber>2001</StockNumber>
            <Make>Ferrari</Make>
            <Model>F355 Spider</Model>
        </Car>
    </Cars>
</CarCollection>
  

и его десериализованных классов объектов, которые были сгенерированы xsd.exe:

 //------------------------------------------------------------------------------
// <auto-generated>
//     Dieser Code wurde von einem Tool generiert.
//     Laufzeitversion:4.0.30319.42000
//
//     Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
//     der Code erneut generiert wird.
// </auto-generated>
//------------------------------------------------------------------------------

using System.Xml.Serialization;

// 
// Dieser Quellcode wurde automatisch generiert von xsd, Version=4.6.1055.0.
// 


/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1055.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)]
public partial class CarCollection : object, System.ComponentModel.INotifyPropertyChanged {

    private CarCollectionCars[] itemsField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("Cars", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public CarCollectionCars[] Items {
        get {
            return this.itemsField;
        }
        set {
            this.itemsField = value;
            this.RaisePropertyChanged("Items");
        }
    }

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName) {
        System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
        if ((propertyChanged != null)) {
            propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
    }
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1055.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
public partial class CarCollectionCars : object, System.ComponentModel.INotifyPropertyChanged {

    private CarCollectionCarsCar[] carField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("Car", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public CarCollectionCarsCar[] Car {
        get {
            return this.carField;
        }
        set {
            this.carField = value;
            this.RaisePropertyChanged("Car");
        }
    }

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName) {
        System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
        if ((propertyChanged != null)) {
            propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
    }
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1055.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
public partial class CarCollectionCarsCar : object, System.ComponentModel.INotifyPropertyChanged {

    private string stockNumberField;

    private string makeField;

    private string modelField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string StockNumber {
        get {
            return this.stockNumberField;
        }
        set {
            this.stockNumberField = value;
            this.RaisePropertyChanged("StockNumber");
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string Make {
        get {
            return this.makeField;
        }
        set {
            this.makeField = value;
            this.RaisePropertyChanged("Make");
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string Model {
        get {
            return this.modelField;
        }
        set {
            this.modelField = value;
            this.RaisePropertyChanged("Model");
        }
    }

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName) {
        System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
        if ((propertyChanged != null)) {
            propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
    }
}
  

Я хочу запросить номер склада, марку и модель класса Car. Поэтому,
Я начал с этого кода:

 XmlSerializer ser = new XmlSerializer(typeof(CarCollection));
CarCollection cars;
using (XmlReader reader = XmlReader.Create(file))
{
    cars = (CarCollection)ser.Deserialize(reader);
    foreach (var item in cars.Items)
    {
        foreach (var carCollection in item.Car)
        {
            carPool.Add(new CarPool()
            {
                Make = carCollection.Make,
                Model = carCollection.Model,
                StockNumber = carCollection.StockNumber
            });
        }
    }
}
  

Однако мне не нравится этот вложенный цикл for. Кто-нибудь знает, как сделать этот запрос более эффективным с помощью LINQ?

Комментарии:

1. I want to query the StockNumber, Make and the Model of the Car class. это означает, что вы хотите получить все данные, которые вы сказали?

2. Да, я хочу получить все данные…

3. Я добавил свой ответ ниже, попробуйте и дайте мне знать 🙂

Ответ №1:

Linq и SelectMany() должны разрешить вложенные циклы:

 // not tested or compiled
using (XmlReader reader = XmlReader.Create(file))
{
    var cars = (CarCollection)ser.Deserialize(reader);

    carPool.AddRange(
       cars.Items.SelectMany(it => it.Car).Select(c => 
            new CarPool()
            {
                Make = c.Make,
                Model = c.Model,
                StockNumber = c.StockNumber
            }) );
}
  

Комментарии:

1. Потрясающе! Спасибо, Хенк! Это тот ответ, который я искал!

Ответ №2:

Если вы хотите анализировать XML и если вы используете XmlSerializer , то вам нужно управлять иерархией классов и его утомительной работой по управлению иерархией классов для сложного и большого xml

Итак, один из вариантов — использовать XDocument .

Вы можете просто выполнить LINQ на XDocument , чтобы получить нужные данные из XML.

Используя XDocument , вы можете напрямую сосредоточиться на своих данных, не управляя структурой классов.

 XDocument xdoc = XDocument.Load(@"Path to your xml file");

var result = (from car in xdoc.Descendants("Car")
              select new
              {
                  StockNumber = car.Element("StockNumber")?.Value,
                  Make = car.Element("Make")?.Value,
                  Model = car.Element("Model")?.Value
              }).ToList();


Console.WriteLine("StockNumbertMakettModel");
Console.WriteLine("----------------------------------------------");
foreach (var item in result)
{
    Console.WriteLine(item.StockNumber   "tt"   item.Make   "tt"   item.Model); ;
}
  

Альтернатива:

Тем не менее, вы хотите десериализовать свой xml с помощью XmlSerializer и классов, тогда ниже приведена структура классов,

 [XmlRoot("Car")]
public class Car
{
    [XmlElement("StockNumber")]
    public string StockNumber { get; set; }
    [XmlElement("Make")]
    public string Make { get; set; }
    [XmlElement("Model")]
    public string Model { get; set; }
}
[XmlRoot("Cars")]
public class Cars
{
    [XmlElement("Car")]
    public List<Car> Car { get; set; }
}
[XmlRoot("CarCollection")]
public class CarCollection
{
    [XmlElement("Cars")]
    public Cars Cars { get; set; }
}
  

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

 XmlSerializer ser = new XmlSerializer(typeof(CarCollection));

CarCollection cars = null;

using (StreamReader reader = new StreamReader(@"Path to your xml file"))
{
    cars = (CarCollection)ser.Deserialize(reader);
}

List<Car> result = cars.Cars.Car.ToList();

//--------------------------Print the result to console--------------

Console.WriteLine("StockNumbertMakettModel");
Console.WriteLine("----------------------------------------------");
foreach (var item in result)
{
    Console.WriteLine(item.StockNumber   "tt"   item.Make   "tt"   item.Model); ;
}

Console.ReadLine();
  

Вывод:

введите описание изображения здесь

Комментарии:

1. Это нормально, но я должен использовать десериализованные классы.

2. Ответ обновлен. пожалуйста, просмотрите раздел » Альтернативный » и дайте мне знать 🙂

3. Это здорово, и это решает проблему! Возможно, следует упомянуть две вещи: 1. Почему reader. Закрыть()? Из-за использования прочитанный объект должен быть удален автоматически. 2. Что, если мне придется использовать xsd.exe ? 😉 Но я принимаю ваш ответ…

4. @PythonNoob, что-нибудь не так с моим ответом? в любом случае, вы можете просто удалить все нужные данные, используя только эту строку => List<Car> result = cars.Cars.Car.ToList();

5. Я особенно искал какое-то решение LINQ.