Время прочтения: 6 мин.

Нередко, в процессе работы с данными, возникает задача чтения XML документов. Ввиду большого количества XML документов, открыть их все одновременно в Excel довольно проблематично. На практике, XML документы загружаются в реляционную базу данных, а дальнейшая работа с документами происходит посредством SQL запросов.

Мы хотим поделиться опытом использования интегрированной среды разработки Visual Studio на языке программирования C# и представить порядок чтения и записи XML документов в табличную форму, представленную форматом CSV. Благодаря своей табличной структуре CSV формат удобен для чтения данных в Excel или для загрузки в реляционную базу данных.

О форматах XML и CSV

XML – аббревиатура от англ. eXTensible Markup Language (пер. расширяемый язык разметки), разработан для хранения и передачи данных. XML документы формируют древовидную структуру, которая начинается с корневого элемента и разветвляется на дочерние элементы.

CSV – аббревиатура от англ. Comma-Separated Values (пер. значения, разделенные запятыми), текстовый формат, предназначенный для представления табличных данных. Строка таблицы соответствует строке текста, которая содержит одно или несколько полей, разделенных запятыми. В нашем примере будем обрабатывать документы в формате XML с данными субъектов малого и среднего предпринимательства (далее — реестр СМП) (источник данных)

Ниже приведен пример XML файла с данными организации:

— в заголовке указана версия XML и кодировка;

— корневой элемент <Файл> содержит поля с информацией о XML файле: количество документов, тип информации, версия формы, идентификатор файла. Корневой элемент содержит дочерние элементы <ИдОтпр> и <Документ>;

— элемент <ИдОтпр> идентификатор отправителя содержит сущность ФИО ответственного с полями «Имя» и «Фамилия»;

— элемент <Документ> содержит информацию о документе: признак нового реестра, категорию, вид, дату включения в реестр, дату состоянию и идентификатор документа. Дочерние элементы представлены узлами <ОргВклМСП>, <СведМН> и <СвОКВЭД> содержащие свой набор полей.

<?xml version="1.0" encoding="UTF-8"?>
<Файл КолДок="900" ТипИнф="РЕЕСТРМСП" ВерсФорм="4.01" ИдФайл="VO_RRMSPSV_XXXX_XXXX_XXXXXXXX_XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX">
     <ИдОтпр>
          <ФИООтв Имя="-" Фамилия="-"/>
    </ИдОтпр>
    <Документ ПризНовМСП="2" КатСубМСП="1" ВидСубМСП="1" ДатаВклМСП="01.12.2016" ДатаСост="01.12.2019" ИдДок="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX">
           <ОргВклМСП ИННЮЛ="0000000000" НаимОргСокр="ООО "НАИМЕНОВАНИЕ ОРГАНИЗАЦИИ"" НаимОрг="ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ "НАИМЕНОВАНИЕ ОРГАНИЗАЦИИ""/>
           <СведМН КодРегион="99">
                <Регион Наим="НАИМЕНОВАНИЕ РЕГИОНА" Тип="ОБЛАСТЬ"/>
                <Город Наим="НАИМЕНОВАНИЕ ГОРОДА" Тип="ГОРОД"/>
        </СведМН>
        <СвОКВЭД>
                <СвОКВЭДОсн ВерсОКВЭД="2014" НаимОКВЭД="Производство прочего грузоподъемного, транспортирующего и погрузочно-разгрузочного оборудования" КодОКВЭД="28.22.9"/>
                <СвОКВЭДДоп ВерсОКВЭД="2014" НаимОКВЭД="Деятельность автомобильного грузового транспорта и услуги по перевозкам" КодОКВЭД="49.4"/>
       </Документ>
</Файл>

Порядок чтения XML документов и их перевода в формат CSV в Visual Studio

  1. Создание проекта Visual Studio

В Visual Studio создадим проект приложения, например, WPF Visual C#.

2. Создание класса C# на основании схемы документа XSD

Схема XSD описывает структуру XML-документа, а также описывает различные ограничения на данные, содержащиеся в документе.

В командной строке запускаем утилиту xsd.exe с аргументом файла XSD:

"C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\x64\xsd.exe" /c structure-10102019.xsd

В результате сформируется файл класса C#:

namespace FinAuditBusinessLogic.Models.XML.VO_RRMSPSV
{   
    /// <remarks/>
    [System.SerializableAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
    [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
    public partial class Файл
    {
        private ФайлИдОтпр идОтпрField;
        private ФайлДокумент[] документField;
        private string идФайлField;
        private decimal версФормField;
        private string типИнфField;
        private ushort колДокField;

Добавляем файла класса в проект решения. Установим пространство имен, которое нам понадобится далее, для примера:

namespace FinAuditBusinessLogic.Models.XML.VO_RRMSPSV

Класс XML документа создан, подключен к проекту и теперь все готово для написания кода по загрузке документов. Далее представлен один из вариантов возможной реализации программного кода.

3. Чтение XML документов

Для чтения текста из файла используем класс File из пространства имен System.IO. Запишем текст из XML файла в переменную:

string xmlInputData = File.ReadAllText(filePath);

Далее, применим сериализацию. Сериализация – это процесс преобразования объекта в поток байтов для сохранения или передачи в память, базу данных или файл. Эта операция предназначена для того, чтобы сохранить состояния объекта для последующего воссоздания при необходимости. Обратный процесс называется десериализацией.

Подключаем пространство имен и десериализуем документы из XML файла в классы:

using FinAuditBusinessLogic.Models.XML.VO_RRMSPSV;

Файл fileModel = ser.Deserialize<Файл>(xmlInputData);

На этом этапе мы получили класс «Файл» с набором всех документов из файла. Теперь в коде мы можем работать с документами из XML файла как с объектами.

4. Подготовка документов для формата CSV

Преобразование свойств документов в список массива объектов:

List<object[]> resultFromFile = ExportFilesToArray(fileModelList);

В реализованном методе ExportFilesToArray в цикле для каждого документа читаем значения свойств и записываем их в список массива объектов:

public List<object[]> ExportFilesToArray(List<Файл> fileModelList)
        {   
            List<object[]> resultArrays = new List<object[]>();
                           
                foreach (var item in fileModelList)
                {
                    foreach (var item2 in item.Документ)
                    {
                        object[] arr = new string[39];

                        arr[0] = item.ИдФайл.ToString();
                        arr[1] = item.ВерсФорм.ToString();
                        arr[2] = item.ТипИнф;
                        arr[3] = item.КолДок.ToString();
                        arr[6] = item2.ИдДок;
                        arr[7] = item2.ДатаСост;
                        arr[8] = item2.ДатаВклМСП;
                        arr[9] = item2.ВидСубМСП.ToString();
                        arr[10] = item2.КатСубМСП.ToString();
                        arr[11] = item2.ПризНовМСП.ToString();

                        if (item2.ИПВклМСП != null)
                        {
                            arr[12] = item2.ИПВклМСП.ИННФЛ.ToString();
                            arr[13] = item2.ИПВклМСП.ФИОИП.Имя;
                            arr[14] = item2.ИПВклМСП.ФИОИП.Отчество;
                            arr[15] = item2.ИПВклМСП.ФИОИП.Фамилия;
                        }

5. Создание документа в CSV формате

 Для заголовка файла в CSV формате формируем названия колонок из наименований свойств документа.

public object[] GetCSVHeader()
        {
            string[] headers = new[] {
                    "ИдФайл",
                    "ВерсФорм",
                    "ТипИнф",
                    "КолДок",
                    "Фамилия",
                    "Имя",
                    "ИдДок",
                    "ДатаСост",

В реализованный метод ArrayToCSV передаем список колонок и на выходе получаем текст в CSV формате. По умолчанию, будем использовать «;» в качестве символа разделителя значений и символом «”» в качестве ограничителя значений и текста.

string CSVHeader = ArrayToCSV(headerList);
public string ArrayToCSV(List<object[]> input)
        {
            StringBuilder sb = new StringBuilder();

            foreach (object[] item in input)
            {
                int length = item.Length;
                for (int i = 0; i < item.Length; i++)
                {
                    sb.Append("\"" + item[i] + "\"");
                    if (i + 1 < length)
                        sb.Append(";");
                    else
                        sb.Append(System.Environment.NewLine);
                }
            }
            return sb.ToString();
        }

Формируем текст в CSV формате из массива объектов созданных из XML документов.

string CSVText = ArrayToCSV(resultFromFile);

При наличии списка дочерних элементов можно использовать прием формирования нескольких строк относящихся к одному документу. Устанавливаем общий ключ для строк документа. На скриншоте ниже представлена часть кода по формированию новых строк для каждого элемента из списка ОКВЭД. Ключевым полем для каждой строки является «ИдДок».

    // следующие строки
    if (item2.СвОКВЭД != null && item2.СвОКВЭД.СвОКВЭДДоп != null)
    {
        foreach (var el3 in item2.СвОКВЭД.СвОКВЭДДоп)
        {
           object[] arr2 = new string[39];
           arr2[6] = item2.ИдДок;
           arr2[28] = el3.КодОКВЭД;
           arr2[29] = el3.НаимОКВЭД;
           arr2[30] = el3.ВерсОКВЭД.ToString();
           resultArrays.Add(arr2); 
        }
    }

6. Сохранение CSV файла

Записываем полученный текст в CSV формате в файл с помощью класса StreamWriter из пространства имен System.IO:

// Запись в файл
using (StreamWriter sw = new StreamWriter(exportedFileFullPath, true,
                                Encoding.GetEncoding(1251)))
{                        
    sw.Write(headerAndText.CSVHeader);
    sw.Write(headerAndText.CSVText);
}

Таким образом, в результате программной обработки из набора XML файлов мы получаем CSV файл. Для загрузки данных на MS SQL Server можно использовать MS SQL Server Management Studio, SSIS пакет, собственный программный код загрузки данных, написанный на одном из языков программирования и другие программные средства.