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

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

1С: как прочитать XML из текста

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

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

Основной инструмент — объект ЧтениеXML в связке с методом УстановитьСтроку(). Он даёт последовательный доступ к узлам документа: элементам, атрибутам, тексту. Для типовых обменов по схеме удобнее механизм XDTO, а для простых разовых выборок иногда достаточно регулярного разбора — но именно ЧтениеXML остаётся универсальным и самым производительным способом.

Ниже разобран рабочий код, типовые сценарии обхода узлов, обработка ошибок формата, особенности кодировки и пространств имён, а также критерии выбора между ЧтениеXML и ЧтениеJSON/XDTO.

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

Объект ЧтениеXML — это потоковый парсер: он не загружает весь документ в память как дерево, а читает его последовательно, узел за узлом. Это важно при разборе больших выгрузок на сотни мегабайт, где построение DOM-подобной структуры привело бы к нехватке памяти.

Минимальный рабочий пример выглядит так:

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

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

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

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

ИмяУзла = Чтение.Имя;

// обработка начала элемента

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

ЗначениеУзла = Чтение.Значение;

КонецЕсли;

КонецЦикла;

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

Метод Прочитать() возвращает Истина, пока в потоке есть очередной узел, и Ложь, когда документ закончился. После каждого вызова доступны свойства текущего узла: Имя, ЛокальноеИмя, Значение, ТипУзла, URIПространстваИмен, Глубина.

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

Какие узлы встречаются и как их различать

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

Тип узлаЧто этоКак обычно обрабатывают
НачалоЭлементаОткрывающий тегЧитают атрибуты, запоминают контекст
КонецЭлементаЗакрывающий тегЗавершают текущую структуру данных
ТекстСодержимое между тегамиСохраняют как значение
АтрибутАтрибут текущего элементаЧитают внутри НачалоЭлемента
Комментарий<!-- ... -->Обычно пропускают
ОбъявлениеXML<?xml version=...?>Пропускают

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

Обратите внимание: пустой элемент вида <Товар/> парсер вернёт как начало элемента со сразу следующим концом элемента, а текст внутри элемента может прийти несколькими узлами подряд, если в нём встречались спецсимволы или CDATA. Поэтому надёжнее собирать значение элемента накоплением, а не брать первый попавшийся текстовый узел.

Разбор вложенной структуры на примере документа

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

Функция РазобратьДокумент(ТекстXML)

Результат = Новый Структура("Номер, Дата, Строки");

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

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

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

ТекущаяСтрока = Неопределено;

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

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

Если Чтение.ЛокальноеИмя = "Документ" Тогда

Результат.Номер = Чтение.ЗначениеАтрибута("Номер");

Результат.Дата = Чтение.ЗначениеАтрибута("Дата");

ИначеЕсли Чтение.ЛокальноеИмя = "Строка" Тогда

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

ИначеЕсли Чтение.ЛокальноеИмя = "Номенклатура"

И ТекущаяСтрока <> Неопределено Тогда

Чтение.Прочитать(); // переходим к тексту

ТекущаяСтрока.Номенклатура = Чтение.Значение;

КонецЕсли;

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

И Чтение.ЛокальноеИмя = "Строка" Тогда

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

ТекущаяСтрока = Неопределено;

КонецЕсли;

КонецЦикла;

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

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

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

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

Числа и даты из XML всегда приходят строками. Даты в каноническом формате 2026-03-15T10:30:00 преобразуются функцией XMLЗначение(Тип("Дата"), СтрокаДаты), числа — обычным Число() с учётом того, что разделитель в XML — точка.

Типичные ошибки
01
Сравнение с Имя вместо ЛокальноеИмя — код ломается, как только в документе появляется префикс пространства имён
02
Чтение Значение на узле НачалоЭлемента — там его нет, текст лежит в отдельном узле Текст
03
Отсутствие Чтение.Закрыть() — при массовой обработке копятся незакрытые объекты и растёт потребление памяти
04
Преобразование даты через Дата(Строка) вместо XMLЗначение — формат ISO так не разбирается

Обработка ошибок и невалидного XML

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

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

Попытка

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

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

// разбор

КонецЦикла;

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

Исключение

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

// запись в журнал регистрации, пропуск пакета

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

Текст исключения обычно содержит позицию ошибки — номер строки и колонки в XML. Это первое, что стоит смотреть при отладке: часто оказывается, что сервис вернул не XML, а HTML-страницу с ошибкой авторизации или текстовое сообщение.

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

Кодировка, BOM и объявление XML

Когда XML читается из строки, кодировка уже определена — строка в 1С хранится в Unicode. Проблемы возникают на шаге раньше: при получении этой строки из файла или HTTP-ответа. Если файл в UTF-8 прочитать как ANSI, кириллица превратится в «кракозябры» ещё до разбора.

Для файлов используйте ЧтениеТекста с явным указанием кодировки: Новый ЧтениеТекста(ИмяФайла, КодировкаТекста.UTF8). Для HTTP-ответов метод ПолучитьТелоКакСтроку() сам подбирает кодировку по заголовкам, но при сомнениях её можно задать явно.

Отдельный нюанс — объявление <?xml version="1.0" encoding="UTF-8"?> внутри строки. При разборе из строки оно игнорируется в части кодировки, но его наличие не мешает. А вот BOM (невидимый символ в начале строки) иногда приводит к ошибке разбора — его стоит удалить через СтрЗаменить(Текст, Символ(65279), ""), если данные пришли из внешнего источника.

Контрольные точки

Как проверить результат

Кириллица в значениях
Норма

Русские буквы читаются корректно

Тревожный признак

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

Начало строки
Норма

Строка начинается с символа < или объявления <?xml

Тревожный признак

В начале HTML или текст ошибки — это не XML

Разбор до конца
Норма

Цикл завершился без исключения

Тревожный признак

Исключение с позицией ошибки — документ обрезан или повреждён

Когда вместо ЧтениеXML использовать XDTO

Ручной потоковый разбор оправдан, когда структура документа простая, нестабильная или заранее не описана схемой. Но если обмен идёт по формализованному формату — EnterpriseData, обмен с сайтом, ЭДО — платформа предоставляет более удобный путь.

Механизм XDTO позволяет прочитать XML из строки в объектную модель одной командой:

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

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

ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(Чтение);

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

После этого данные доступны как свойства объекта: ОбъектXDTO.Документ.Номер, а коллекции обходятся обычным циклом. Если в конфигурации описан пакет XDTO под конкретный формат, фабрика ещё и проверит соответствие схеме — невалидный документ будет отклонён с понятной диагностикой.

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

ЧтениеXML вручную

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

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

Подходит для обменов по известной схеме; меньше кода, валидация по пакету XDTO, но требует описания схемы и держит объектную модель в памяти

DOM (ПостроительDOM)

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

Проверка результата и отладка

После разбора убедитесь, что данные действительно извлечены: выведите ключевые поля через Сообщить() или запишите в журнал регистрации. Для тестирования удобно держать под рукой эталонный XML-фрагмент и прогонять функцию разбора на нём после каждого изменения кода.

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

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

Сообщить(Строка(Чтение.ТипУзла) + " | "

+ Чтение.Имя + " | " + Чтение.Значение);

КонецЦикла;

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

Итог

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

XML из строки читается через ЧтениеXML и УстановитьСтроку с обходом узлов в цикле Прочитать(). Сравнивайте узлы по ЛокальноеИмя, оборачивайте разбор в попытку, закрывайте объект, а для обменов по схеме используйте ФабрикаXDTO.ПрочитатьXML.

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

Чем чтение из строки отличается от чтения из файла?

Только способом передачи данных парсеру: вместо УстановитьСтроку(Текст) используется ОткрытьФайл(Путь). Вся дальнейшая логика обхода узлов идентична. Чтение из строки избавляет от необходимости создавать временный файл, что важно на сервере, где права на диск могут быть ограничены.

Как прочитать значение атрибута элемента?

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

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

Сравнивайте узлы по свойству ЛокальноеИмя, а не Имя — тогда префикс вида ns: не сломает логику. Если нужно различать одноимённые элементы из разных пространств, дополнительно проверяйте свойство URIПространстваИмен.

Почему Прочитать() выдаёт ошибку на первом же узле?

Чаще всего строка не является XML: сервис вернул HTML-страницу ошибки, пустой ответ или текст в другой кодировке. Проверьте первые символы строки до разбора. Реже причина — символ BOM в начале строки, который нужно удалить.

Можно ли прочитать XML без объявления <?xml ...?>?

Да, объявление необязательно. Парсер корректно разберёт документ, начинающийся сразу с корневого элемента, если он синтаксически валиден. Объявление важно в основном при чтении из файла, где по нему определяется кодировка.

Как разобрать очень большой XML без нехватки памяти?

Используйте именно потоковый ЧтениеXML и обрабатывайте записи по одной: сформировали объект — записали в базу — очистили переменные. Не накапливайте весь результат в массиве или таблице значений, если документ содержит сотни тысяч строк. XDTO и DOM для таких объёмов не подходят, так как строят модель целиком в памяти.