При интеграции систем и обмене данными программисты 1С часто сталкиваются с разбором XML-файлов. Одной из неочевидных проблем для начинающих разработчиков становится чтение текстового значения элемента, у которого одновременно присутствуют XML-атрибуты. Типичный пример такой строки выглядит следующим образом:
<БазоваяЕдиница Код="796" НаименованиеПолное="штука" МеждународноеСокращение="PCE">шт</БазоваяЕдиница>
При парсинге такой строки легко получить значения атрибутов (Код, НаименованиеПолное, МеждународноеСокращение), но у многих возникает вопрос: как добраться до самого текстового значения «шт»?
В этой статье мы подробно разберем четыре практических способа решения этой задачи: от классического последовательного чтения до работы с объектной моделью DOM и механизмами XDTO.
Этот способ является наиболее производительным и не требовательным к оперативной памяти, так как файл читается последовательно, поток за потоком. Чтобы понять, как получить значение «шт», нам нужно разобраться, как именно платформенный объект ЧтениеXML видит XML-структуру.
Для последовательного парсера строка с элементом и его текстовым содержимым — это не один узел, а три разных узла, следующих друг за другом:
Значение содержится наша строка "шт".Проанализируем классический код обхода такого дерева:
ПутьКФайлу = "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.Закрыть();
Если размер обрабатываемого файла невелик, то работа через последовательное чтение может показаться избыточно сложной из-за необходимости контролировать состояния указателя. В таких ситуациях гораздо проще использовать объектную модель документа (DOM). Этот подход загружает XML-структуру в оперативную память в виде дерева объектов, к узлам которого можно обращаться напрямую.
Выясним, как выглядит решение задачи с помощью ПостроительDOM:
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКФайлу);
// Загружаем XML в дерево DOM
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
// Находим все узлы "БазоваяЕдиница" в документе
ЭлементыБазовыхЕдиниц = ДокументDOM.ПолучитьЭлементыПоИмени("БазоваяЕдиница");
Для Каждого Элемент Из ЭлементыБазовыхЕдиниц Цикл
// Получаем значения атрибутов по их именам
Код = Элемент.Атрибуты.ПолучитьИменованныйЭлемент("Код").Значение;
МеждународноеСокращение = Элемент.Атрибуты.ПолучитьИменованныйЭлемент("МеждународноеСокращение").Значение;
// Получаем текстовое значение "шт" напрямую через специальное свойство
ЗначениеЕдиницы = Элемент.ТекстовоеСодержимое;
Сообщить("Единица: " + ЗначениеЕдиницы + " (Код: " + Код + ")");
КонецЦикла;
ЧтениеXML.Закрыть();
Преимущество метода: Код получается максимально чистым, понятным и не зависит от порядка следования тегов в файле.
Многие разработчики предпочитают использовать фабрику 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-схемы файла.
Если для обмена данными вы используете полноценную XSD-схему (импортированную в пакет XDTO вашей конфигурации или созданную динамически), платформа 1С предоставляет встроенный механизм связывания текста элемента со свойствами объекта.
Чтобы значение «шт» автоматически считывалось в свойство (например, с именем __content), при проектировании схемы XSD необходимо соблюдать важные правила платформы:
Form = Text).Код, НаименованиеПолное, МеждународноеСокращение) обязаны иметь форму представления «Атрибут» (Form = Attribute).Если схема настроена верно, чтение выполняется стандартным образом, а текстовое значение будет доступно напрямую:
// Считаем данные с использованием зарегистрированного пакета XDTO
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКФайлу);
// Типизированное чтение объекта по схеме
БазоваяЕдиница = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ФабрикаXDTO.Тип("http://www.yourdomain.ru/units", "БазоваяЕдиница"));
// Теперь текстовое значение "шт" доступно напрямую через свойство __content
ЗначениеШт = БазоваяЕдиница.__content;
Код = БазоваяЕдиница.Код;
Сообщить("Единица: " + ЗначениеШт + ", Код: " + Код);
ЧтениеXML.Закрыть();
Мы рассмотрели различные подходы к разбору XML-строк со смешанным содержимым. Выбор конкретного инструмента зависит от архитектуры вашей задачи:
ЧтениеXML и метод ПрочитатьСодержимоеКакСтроку().DOM.Последовательностью() объекта или правильно настраивайте свойства «Текст/Атрибут» в схемах XSD.