К статье
Практический материал

Разработка и Конфигурация · 12 мин

Как прочитать строку как XML в 1С

Как прочитать строку как XML в 1С: объект ЧтениеXML, УстановитьСтроку, построчный разбор узлов, работа с атрибутами, обработка ошибок и типовые примеры кода.

Задача прочитать строку как XML в 1С возникает при обмене данными с веб-сервисами, при получении ответов от API, при загрузке файлов из внешних систем и при разборе настроек, хранящихся в виде XML-текста. Встроенный язык платформы предоставляет для этого объект ЧтениеXML, который работает как последовательный парсер: он читает документ узел за узлом и позволяет извлекать имена элементов, атрибуты и текстовое содержимое.

Ключевой момент: чтобы разобрать XML из строковой переменной, а не из файла, используется метод УстановитьСтроку(). Если же данные лежат в файле на диске, применяется ОткрытьФайл(). Дальнейшая логика разбора в обоих случаях одинакова — цикл Прочитать() с проверкой типа текущего узла.

Ниже разобраны базовый пример кода, работа с атрибутами и вложенными элементами, обработка ошибок формата, а также альтернативные способы — через ДокументDOM и ФабрикаXDTO, которые удобнее в отдельных сценариях.

Базовый пример: ЧтениеXML и УстановитьСтроку

Объект ЧтениеXML создаётся конструктором Новый ЧтениеXML. После этого строку с XML-содержимым передают методу УстановитьСтроку(). Парсер встаёт на начало документа, и дальше каждый вызов Прочитать() сдвигает позицию к следующему узлу, пока метод не вернёт Ложь — признак конца документа.

СтрокаXML = "<Товары><Товар Код=""001""><Наименование>Кабель</Наименование></Товар></Товары>";

Чтение = Новый ЧтениеXML;

Чтение.УстановитьСтроку(СтрокаXML);

Пока Чтение.Прочитать() Цикл

Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда

Сообщить("Начало элемента: " + Чтение.Имя);

ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.Текст Тогда

Сообщить("Текст: " + Чтение.Значение);

ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда

Сообщить("Конец элемента: " + Чтение.Имя);

КонецЕсли;

КонецЦикла;

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

После завершения разбора вызовите Закрыть() — это освобождает ресурсы парсера. Если строка содержит некорректный XML, исключение возникнет либо при УстановитьСтроку(), либо при первом вызове Прочитать(), поэтому боевой код всегда оборачивают в Попытка...Исключение.

bsl
Чтение = Новый ЧтениеXML;
Чтение.УстановитьСтроку(СтрокаXML);
Пока Чтение.Прочитать() Цикл
    Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
        // обработка узла
    КонецЕсли;
КонецЦикла;
Чтение.Закрыть();

Какие типы узлов встречаются при разборе

Парсер проходит документ последовательно и для каждого шага заполняет свойство ТипУзла. Понимание типов узлов — основа корректного разбора, потому что обращение к Имя или Значение имеет смысл только для соответствующих типов.

  • НачалоЭлемента — открывающий тег; доступны Имя, атрибуты, URIПространстваИмен;
  • КонецЭлемента — закрывающий тег; доступно Имя;
  • Текст — текстовое содержимое между тегами; доступно Значение;
  • НачалоДокумента и КонецДокумента — служебные позиции;
  • Комментарий, ИнструкцияОбработки, ОбъявлениеXML — обычно пропускаются.

Частая ошибка новичков — ожидать, что текст элемента доступен сразу на узле НачалоЭлемента. На самом деле текст приходит отдельным узлом типа Текст следующим шагом цикла. Для упрощения есть метод ПрочитатьЗначение()-подобная логика не предусмотрена, но можно использовать Пропустить(), чтобы перепрыгнуть через поддерево, которое не нужно.

Чтение атрибутов и текстового содержимого

Когда парсер стоит на узле НачалоЭлемента, атрибуты доступны тремя способами: по имени через ПолучитьАтрибут("ИмяАтрибута"), по индексу через ЗначениеАтрибута(Индекс) с учётом КоличествоАтрибутов(), либо перебором через ПрочитатьАтрибут(). Если атрибут отсутствует, ПолучитьАтрибут вернёт Неопределено — обязательно проверяйте результат перед использованием.

Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента

И Чтение.Имя = "Товар" Тогда

КодТовара = Чтение.ПолучитьАтрибут("Код");

Если КодТовара = Неопределено Тогда

КодТовара = "";

КонецЕсли;

// Перебор всех атрибутов

Пока Чтение.ПрочитатьАтрибут() Цикл

Сообщить(Чтение.Имя + " = " + Чтение.Значение);

КонецЦикла;

КонецЕсли;

Для чтения текстового содержимого простого элемента удобен приём: на узле НачалоЭлемента вызвать Прочитать() ещё раз и проверить, что следующий узел — Текст. Тогда Чтение.Значение даст содержимое. Все значения приходят как строки: числа и даты нужно преобразовывать вручную через Число(), Дата() или XMLЗначение для типов, сериализованных по правилам XDTO.

Разбор вложенной структуры: практический сценарий

Реальные XML-документы имеют иерархию: документ — табличная часть — строки. Правильный подход — отслеживать контекст через локальные переменные и сбрасывать их на закрывающих тегах. Разберём пример загрузки списка товаров в массив структур.

Функция РазобратьТовары(СтрокаXML) Экспорт

Результат = Новый Массив;

ТекущийТовар = Неопределено;

Чтение = Новый ЧтениеXML;

Чтение.УстановитьСтроку(СтрокаXML);

Пока Чтение.Прочитать() Цикл

Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда

Если Чтение.Имя = "Товар" Тогда

ТекущийТовар = Новый Структура("Код,Наименование");

ТекущийТовар.Код = Чтение.ПолучитьАтрибут("Код");

ИначеЕсли Чтение.Имя = "Наименование" И ТекущийТовар <> Неопределено Тогда

Чтение.Прочитать();

Если Чтение.ТипУзла = ТипУзлаXML.Текст Тогда

ТекущийТовар.Наименование = Чтение.Значение;

КонецЕсли;

КонецЕсли;

ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента

И Чтение.Имя = "Товар" Тогда

Результат.Добавить(ТекущийТовар);

ТекущийТовар = Неопределено;

КонецЕсли;

КонецЦикла;

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

Возврат Результат;

КонецФункции

Обратите внимание на три приёма: текущий объект создаётся на открывающем теге, наполняется на дочерних узлах и фиксируется в результате на закрывающем. Такая схема масштабируется на любую глубину вложенности — для более сложных документов добавляют переменную текущего раздела или стек контекстов.

Порядок действий
  1. 1
    Сформируйте или получите строку с XML-содержимым
  2. 2
    Создайте объект: Новый ЧтениеXML
  3. 3
    Вызовите УстановитьСтроку(СтрокаXML) внутри Попытка...Исключение
  4. 4
    В цикле Прочитать() проверяйте ТипУзла и Имя элемента
  5. 5
    Извлекайте атрибуты через ПолучитьАтрибут, текст — на узле ТипУзлаXML.Текст
  6. 6
    Закройте чтение методом Закрыть() и проверьте собранные данные

Обработка ошибок и проверка результата

Строка, пришедшая извне, не гарантированно является валидным XML. Типичные проблемы: обрезанный документ, незакрытые теги, недопустимые символы, неверная кодировка, HTML вместо XML. Любая из них вызовет исключение, поэтому разбор всегда помещают в защищённый блок.

Чтение = Новый ЧтениеXML;

Попытка

Чтение.УстановитьСтроку(СтрокаXML);

Пока Чтение.Прочитать() Цикл

// разбор

КонецЦикла;

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

Исключение

ТекстОшибки = ОписаниеОшибки();

ЗаписьЖурналаРегистрации("ЗагрузкаXML",

УровеньЖурналаРегистрации.Ошибка,,, ТекстОшибки);

КонецПопытки;

Помимо технической валидности проверяйте смысловую: наличие обязательных элементов, заполненность ключевых атрибутов, соответствие количества загруженных строк ожидаемому. Полезно логировать не только факт ошибки, но и фрагмент строки, на котором разбор прервался, — это сильно ускоряет поиск причины при обмене с внешними системами.

Типичные ошибки
01
Чтение без Попытка...Исключение — один битый ответ внешнего сервиса останавливает всю обработку
02
Ожидание текста на узле НачалоЭлемента — значение элемента приходит отдельным узлом Текст
03
Использование атрибута без проверки на Неопределено — ошибка при отсутствии атрибута
04
Сравнение имён элементов без учёта регистра и пространств имён — узлы не находятся
05
Отсутствие вызова Закрыть() — утечка ресурсов при массовой обработке

Альтернативы: ДокументDOM и ФабрикаXDTO

Последовательный парсер ЧтениеXML — не единственный способ. Встроенный язык предлагает ещё два механизма, которые в ряде задач удобнее.

ДокументDOM загружает весь документ в память как дерево и позволяет обращаться к элементам по XPath-подобным путям. Подходит, когда нужен произвольный доступ к узлам и документ умеренного размера:

Чтение = Новый ЧтениеXML;

Чтение.УстановитьСтроку(СтрокаXML);

Построитель = Новый ПостроительDOM;

Документ = Построитель.Прочитать(Чтение);

Узлы = Документ.ПолучитьЭлементыПоИмени("Товар");

Для Каждого Узел Из Узлы Цикл

Код = Узел.ПолучитьАтрибут("Код");

КонецЦикла;

ФабрикаXDTO и функции ПрочитатьXML применяются, когда XML соответствует известной схеме: платформа сама преобразует документ в объект с типизированными свойствами. Это стандартный путь для обменов EnterpriseData, веб-сервисов и сериализованных объектов конфигурации.

Сравнение вариантов

ЧтениеXML

Последовательный разбор, минимальный расход памяти. Подходит для больших документов и потоковой загрузки, но код разбора вложенных структур громоздкий

ДокументDOM

Дерево в памяти со случайным доступом к узлам. Удобен для небольших документов и выборок по имени элемента, но требует больше памяти

ФабрикаXDTO / ПрочитатьXML

Автоматическое преобразование в типизированные объекты по схеме. Лучший выбор для стандартных форматов обмена, но требует описанной схемы

Когда какой способ выбрать

Выбор механизма зависит от размера документа, наличия схемы и характера доступа к данным. Для однопроходной загрузки больших файлов — только ЧтениеXML. Для разбора короткого ответа API с необходимостью доставать значения из разных веток — удобнее ДокументDOM. Для стандартных обменов и веб-сервисов — ФабрикаXDTO.

Если строка пришла из файла, сначала прочитайте файл в строку через ЧтениеТекста с указанием кодировки, либо сразу используйте Чтение.ОткрытьФайл() — это надёжнее, так как парсер сам определит кодировку по объявлению XML.

Маршрут решения

Как выбрать действие

XML большой и читается один раз последовательноИспользуйте ЧтениеXML с циклом Прочитать()
Нужно многократно обращаться к разным узлам небольшого документаЗагрузите строку в ДокументDOM через ПостроительDOM
Документ соответствует схеме XDTO или это ответ веб-сервисаПрименяйте ПрочитатьXML или ФабрикаXDTO
Строка приходит из внешней системы и её формат не гарантированОберните разбор в Попытка...Исключение и логируйте ОписаниеОшибки()
Итог

Что важно запомнить

Строку разбирают через ЧтениеXML с методом УстановитьСтроку и циклом Прочитать(), проверяя ТипУзла. Атрибуты читают на узле НачалоЭлемента, текст — на узле Текст. Разбор всегда защищают обработкой исключений, а для дерева в памяти и типизированных схем есть ДокументDOM и ФабрикаXDTO.

Частые вопросы

Чем УстановитьСтроку отличается от ОткрытьФайл?

УстановитьСтроку принимает XML-содержимое из строковой переменной, уже находящейся в памяти. ОткрытьФайл читает данные напрямую из файла на диске. Логика дальнейшего разбора идентична, но при работе с файлом парсер сам учитывает кодировку из объявления XML.

Почему ПолучитьАтрибут возвращает Неопределено?

Так происходит, если атрибут с указанным именем отсутствует в текущем элементе либо имя указано с ошибкой в регистре символов — имена атрибутов чувствительны к регистру. Перед использованием значения всегда проверяйте его на Неопределено.

Как пропустить ненужный фрагмент документа?

На узле НачалоЭлемента вызовите метод Пропустить() — парсер перейдёт сразу к концу текущего элемента, минуя всё его содержимое. Это быстрее, чем вручную отслеживать вложенность ненужной ветки.

Как преобразовать строковое значение из XML в дату или число?

Все значения из ЧтениеXML приходят строками. Для чисел используйте Число(), для дат — конструктор Дата() или функцию XMLЗначение с указанием типа, если значение записано в каноническом формате XDTO (например, 2026-01-15T10:30:00).

Что делать, если XML содержит пространства имён?

Свойство Имя возвращает локальное имя без префикса, а пространство доступно через URIПространстваИмен. Если в документе есть элементы с одинаковыми локальными именами из разных пространств, сравнивайте оба свойства, иначе разбор перепутает узлы.

Можно ли прочитать XML в управляемой форме на клиенте?

Да, ЧтениеXML доступен на тонком и веб-клиенте. Однако тяжёлый разбор больших документов лучше выполнять на сервере, чтобы не блокировать интерфейс пользователя и не передавать большие строки между клиентом и сервером.