Как прочитать текстовое значение XML-элемента с атрибутами в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При интеграции систем и обмене данными программисты 1С часто сталкиваются с разбором XML-файлов. Одной из неочевидных проблем для начинающих разработчиков становится чтение текстового значения элемента, у которого одновременно присутствуют XML-атрибуты. Типичный пример такой строки выглядит следующим образом:


<БазоваяЕдиница Код="796" НаименованиеПолное="штука" МеждународноеСокращение="PCE">шт</БазоваяЕдиница>

При парсинге такой строки легко получить значения атрибутов (Код, НаименованиеПолное, МеждународноеСокращение), но у многих возникает вопрос: как добраться до самого текстового значения «шт»?

В этой статье мы подробно разберем четыре практических способа решения этой задачи: от классического последовательного чтения до работы с объектной моделью DOM и механизмами XDTO.

Способ 1. Последовательное чтение через ЧтениеXML (Оптимально для больших файлов)

Этот способ является наиболее производительным и не требовательным к оперативной памяти, так как файл читается последовательно, поток за потоком. Чтобы понять, как получить значение «шт», нам нужно разобраться, как именно платформенный объект ЧтениеXML видит XML-структуру.

Для последовательного парсера строка с элементом и его текстовым содержимым — это не один узел, а три разных узла, следующих друг за другом:

  1. НачалоЭлемента (имя узла — "БазоваяЕдиница"). На этом шаге нам доступны только атрибуты. Самого слова "шт" здесь еще нет.
  2. Текст (содержимое узла). На этом шаге в свойстве Значение содержится наша строка "шт".
  3. КонецЭлемента (закрывающий тег "БазоваяЕдиница").

Проанализируем классический код обхода такого дерева:


ПутьКФайлу = "C:\temp\units.xml";
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКФайлу);

Пока ЧтениеXML.Прочитать() Цикл
    // Проверяем, что мы находимся в начале нужного элемента
    Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И ЧтениеXML.Имя = "БазоваяЕдиница" Тогда
        
        // Читаем атрибуты элемента
        Код = ЧтениеXML.ПолучитьАтрибут("Код");
        МеждународноеСокращение = ЧтениеXML.ПолучитьАтрибут("МеждународноеСокращение");
        
        Сообщить("Атрибут Код: " + Код);
        Сообщить("Атрибут Сокращение: " + МеждународноеСокращение);
        
        // Переходим к следующему узлу, который содержит текст элемента
        Если ЧтениеXML.Прочитать() И ЧтениеXML.ТипУзла = ТипУзлаXML.Текст Тогда
            ЗначениеЭлемента = ЧтениеXML.Значение; // Получим "шт"
            Сообщить("Текстовое значение элемента: " + ЗначениеЭлемента);
        КонецЕсли;
        
    КонецЕсли;
КонецЦикла;

ЧтениеXML.Закрыть();

Для упрощения этой процедуры в 1С реализован отличный встроенный метод ПрочитатьСодержимоеКакСтроку(). Если принудительно вызвать его в момент нахождения на узле НачалоЭлемента, платформа сама считает весь вложенный текст и автоматически переведет указатель чтения на закрывающий тег. Разберем этот элегантный вариант:


ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКФайлу);

Пока ЧтениеXML.Прочитать() Цикл
    Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И ЧтениеXML.Имя = "БазоваяЕдиница" Тогда
        
        // Получаем атрибуты
        Код = ЧтениеXML.ПолучитьАтрибут("Код");
        
        // Считываем текстовое содержимое "шт" и сдвигаем указатель
        ЗначениеЭлемента = ЧтениеXML.ПрочитатьСодержимоеКакСтроку(); 
        
        Сообщить("Код: " + Код + ", Значение: " + ЗначениеЭлемента);
        
    КонецЕсли;
КонецЦикла;

ЧтениеXML.Закрыть();

Способ 2. Объектная модель DOM (Наиболее удобный для файлов до 100 МБ)

Если размер обрабатываемого файла невелик, то работа через последовательное чтение может показаться избыточно сложной из-за необходимости контролировать состояния указателя. В таких ситуациях гораздо проще использовать объектную модель документа (DOM). Этот подход загружает XML-структуру в оперативную память в виде дерева объектов, к узлам которого можно обращаться напрямую.

Выясним, как выглядит решение задачи с помощью ПостроительDOM:


ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКФайлу);

// Загружаем XML в дерево DOM
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);

// Находим все узлы "БазоваяЕдиница" в документе
ЭлементыБазовыхЕдиниц = ДокументDOM.ПолучитьЭлементыПоИмени("БазоваяЕдиница");

Для Каждого Элемент Из ЭлементыБазовыхЕдиниц Цикл
    
    // Получаем значения атрибутов по их именам
    Код = Элемент.Атрибуты.ПолучитьИменованныйЭлемент("Код").Значение;
    МеждународноеСокращение = Элемент.Атрибуты.ПолучитьИменованныйЭлемент("МеждународноеСокращение").Значение;
    
    // Получаем текстовое значение "шт" напрямую через специальное свойство
    ЗначениеЕдиницы = Элемент.ТекстовоеСодержимое; 
    
    Сообщить("Единица: " + ЗначениеЕдиницы + " (Код: " + Код + ")");
    
КонецЦикла;

ЧтениеXML.Закрыть();

Преимущество метода: Код получается максимально чистым, понятным и не зависит от порядка следования тегов в файле.

Способ 3. Чтение XDTO без схемы (Секрет «Последовательности»)

Многие разработчики предпочитают использовать фабрику XDTO для быстрого преобразования XML в объектную модель 1С. Однако при чтении файла без предварительно загруженной XSD-схемы (нетипизированное чтение) возникает неприятная проблема: значение «шт» пропадает из свойств полученного ОбъектXDTO.

Выясним причину этого поведения. Когда 1С считывает XML-документ без схемы, элементы, имеющие одновременно и атрибуты, и текстовое значение, приводятся к универсальному типу данных xsd:anyType со смешанным содержимым. При этом текстовое значение не помещается в стандартное свойство __content, а переносится в так называемую последовательность объекта XDTO.

Чтобы извлечь текстовое значение в данном случае, нам нужно использовать следующий код:


ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКФайлу);

// Чтение объекта без использования явной схемы
ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);

// Допустим, мы получили объект "БазоваяЕдиница"
// Атрибуты доступны стандартным образом:
Код = ОбъектXDTO.Код;

// Добираемся до значения "шт" через последовательность объекта:
ЗначениеШт = "";
Последовательность = ОбъектXDTO.Последовательность();
Если Последовательность.Количество() > 0 Тогда
    ЗначениеШт = Последовательность.ПолучитьТекст(0);
КонецЕсли;

Сообщить("Значение через последовательность: " + ЗначениеШт);
ЧтениеXML.Закрыть();

Этот простой секрет позволяет успешно использовать лаконичный механизм XDTO даже в тех случаях, когда у вас нет готовой XSD-схемы файла.

Способ 4. Использование XDTO со схемой XSD

Если для обмена данными вы используете полноценную XSD-схему (импортированную в пакет XDTO вашей конфигурации или созданную динамически), платформа 1С предоставляет встроенный механизм связывания текста элемента со свойствами объекта.

Чтобы значение «шт» автоматически считывалось в свойство (например, с именем __content), при проектировании схемы XSD необходимо соблюдать важные правила платформы:

Если схема настроена верно, чтение выполняется стандартным образом, а текстовое значение будет доступно напрямую:


// Считаем данные с использованием зарегистрированного пакета XDTO
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКФайлу);

// Типизированное чтение объекта по схеме
БазоваяЕдиница = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ФабрикаXDTO.Тип("http://www.yourdomain.ru/units", "БазоваяЕдиница"));

// Теперь текстовое значение "шт" доступно напрямую через свойство __content
ЗначениеШт = БазоваяЕдиница.__content;
Код = БазоваяЕдиница.Код;

Сообщить("Единица: " + ЗначениеШт + ", Код: " + Код);
ЧтениеXML.Закрыть();

Резюме

Мы рассмотрели различные подходы к разбору XML-строк со смешанным содержимым. Выбор конкретного инструмента зависит от архитектуры вашей задачи:

← На главную