Распарсить XML-файл с помощью c#

348
18 июня 2017, 14:53

Здравствуйте. У меня в проекте ASP.NET создаётся xml файл. Потом он пишется в таблицу базы данных Oracle. Потом отдельным консольным приложением я его оттуда читаю и должен разбить назад на данные по полям. И записать эти поля уже в итоговую таблицу где они должны храниться. Вот как выглядит мой xml-ка.

<?xml version="1.0" encoding="utf-8"?>
<SteelSheet>
  <Fuse>1500</Fuse>
  <SteelGrades>Криогенная</SteelGrades>
  <Storage>США</Storage>
  <Length>200</Length>
  <Width>100</Width>
  <Thickness>50</Thickness>
  <ShippingDate>25.03.2015</ShippingDate>
  <Acomment>Комментарий</Acomment>
  <DateManufacture>13.01.2015</DateManufacture>
</SteelSheet>

А вот как я её читаю:

class Program
    {
        static void Main(string[] args)
        {
            String str = "select T.xmldoc.getClobVal() as name from Transfer_table T";
            using (OracleConnection con = new OracleConnection("Data Source=XE;User ID=Mydb;Password=111292;Unicode=True"))
            {
                con.Open();
                using (OracleCommand com = new OracleCommand(str, con))
                {
                    using (OracleDataReader reader = com.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            String xml = reader.GetString(0);
                            Console.WriteLine(xml);
                        }
                    }
                }
            }
            Console.ReadKey();
        }
    }

И мне нужно вытащить чисто значения которые между тегов. 1500 отсюда нужно вытащить только 1500 в соответствующую переменную fuse. И так далее всю xml-ку. Можете подсказать как это не сложно и не затратно сделать? Может у кого то есть наброски кода. Как это можно сделать. Спасибо заранее.

Answer 1

В вашем конкретном случае есть несколько подходов.
Я постараюсь описать их максимально доступно.

1. Десериализация XML с помощью XmlSerializer

Копируете текст этой XML в буфер обмена.
Открываете Visual Studio, меню Edit - Paste Special - Paste XML As Classes.
Студия распарсит вашу XML-ку и создаст её объектную модель, в данном случае это будет всего один класс, так как XML имеет довольно простую структуру.
У меня появился такой код:

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class SteelSheet
{
    private ushort fuseField;
    private string steelGradesField;
    private string storageField;
    private byte lengthField;
    private byte widthField;
    private byte thicknessField;
    private string shippingDateField;
    private string acommentField;
    private string dateManufactureField;
    /// <remarks/>
    public ushort Fuse
    {
        get
        {
            return this.fuseField;
        }
        set
        {
            this.fuseField = value;
        }
    }
    /// <remarks/>
    public string SteelGrades
    {
        get
        {
            return this.steelGradesField;
        }
        set
        {
            this.steelGradesField = value;
        }
    }
    /// <remarks/>
    public string Storage
    {
        get
        {
            return this.storageField;
        }
        set
        {
            this.storageField = value;
        }
    }
    /// <remarks/>
    public byte Length
    {
        get
        {
            return this.lengthField;
        }
        set
        {
            this.lengthField = value;
        }
    }
    /// <remarks/>
    public byte Width
    {
        get
        {
            return this.widthField;
        }
        set
        {
            this.widthField = value;
        }
    }
    /// <remarks/>
    public byte Thickness
    {
        get
        {
            return this.thicknessField;
        }
        set
        {
            this.thicknessField = value;
        }
    }
    /// <remarks/>
    public string ShippingDate
    {
        get
        {
            return this.shippingDateField;
        }
        set
        {
            this.shippingDateField = value;
        }
    }
    /// <remarks/>
    public string Acomment
    {
        get
        {
            return this.acommentField;
        }
        set
        {
            this.acommentField = value;
        }
    }
    /// <remarks/>
    public string DateManufacture
    {
        get
        {
            return this.dateManufactureField;
        }
        set
        {
            this.dateManufactureField = value;
        }
    }
}

В принципе с этим можно уже работать, но я рекомендую внимательно изучить этот класс и отрефакторить его:
Во-первых, используя "плюшки" современных версий C# можно избавиться от лишних полей, заменив их автосвойствами, например следующий код:

private ushort fuseField;
public ushort Fuse
{
    get
    {
        return this.fuseField;
    }
    set
    {
        this.fuseField = value;
    }
}

Можно заменить на одно автосвойство:

public ushort Fuse { get; set; }

Внимание, это делать нужно только если на ваши свойства не будет наложена никакая "бизнес-логика".
Во-вторых, проверьте правильно ли студия вывела типы для ваших свойств, например, если Fuse может быть также отрицательным числом, имеет смысл изменить тип свойства на short/int/long вместо беззнакового ushort.
И т. д.

Теперь мы можем воспользоваться этой моделью и десериализовать ее:

XmlSerializer serializer = new XmlSerializer(typeof(SteelSheet));
SteelSheet steelSheet;
using (var sr = new StringReader(xml))
    steelSheet = (SteelSheet)serializer.Deserialize(sr);

Теперь у нас в steelSheet готовый объект, представляющий нашу XML и им можно пользоваться:

Console.WriteLine(steelSheet.Fuse);
2. Использование технологии LinqToXml

В этом подходе вам не понадобится создавать объектную модель вашей XML, что уменьшит код, но с другой стороны усложнит немного логику и не даст удобства использования полноценного объекта (типизация, подсказки IntelliSense).
Давайте просто загрузим нашу XML в объект типа XDocument:

XDocument doc;
using (var sr = new StringReader(xml))
    doc = XDocument.Load(sr);

Всё! Теперь можно извлечь любой элемент/атрибут просто пройдя по дереву XML (главное не ошибиться с именами):

Console.WriteLine((int)doc.Element("SteelSheet").Element("Fuse"));

или:

Console.WriteLine((int)doc.Root.Element("Fuse"));
3. Использование средств, предоставляемых драйвером ODP.NET по извлечению полей типа XmlType

Если вы используете новый Official Oracle ODP.NET, Managed Driver, а я вам рекомендую использовать именно его, вы можете воспользоваться методом GetOracleXmlType класса OracleDataReader.
В этом случае вам не нужно кастовать XmlType в строку на стороне сервера:

select T.xmldoc from Transfer_table T

тогда код чтения перепишите так:

XmlDocument doc = reader.GetOracleXmlType(0).GetXmlDocument();

т.е. на выходе получите уже готовый экземпляр XmlDocument, хотя он немного устарел и немного более тяжеловеснее чем XDocument, но, с другой стороны, работать с ним на стороне клиента может быть выгоднее чем кастовать XmlType в строку на стороне сервера (а может и нет - надо проверять):

int fuse = int.Parse(doc["SteelSheet"]["Fuse"].InnerText);
Console.WriteLine(fuse);
Answer 2

Считаю что стоит предупредить автора вопроса, что возможно выбран не совсем правильный подход к хранению информации. Т.к. у вас используется БД, возможно стоит создать отдельную таблицу со всеми этими полями (что у вас в xml), и уже выгружать данные запросами к БД, например используя entity framework. Это будет более правильно.

READ ALSO
C# string.Compare

C# string.Compare

при сравнении данным методом "а" строковой и "В", будет ли метод использовать код символов в юникод? У а – 97, у В – 66Значит если сравнить их без...

224
Пусть разработчика с чего начать? [требует правки]

Пусть разработчика с чего начать? [требует правки]

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

225
Помогите решить задачу C#

Помогите решить задачу C#

Не могу придумать решение к данной задаче

227
Вывод текста с ComboBox на TextBox

Вывод текста с ComboBox на TextBox

Нужно реализовать выбор через ComboBox нужной строки и сделать так чтобы он выводился в ReadOnly TextBox

358