Разбор XML-файла средствами встроенного языка 1С:Предприятия 8.3

· 10 мин

Содержание

Распарсить XML в 1С можно тремя способами: потоково через объект ЧтениеXML, целиком в дерево через ПостроительDOM или в объекты через ФабрикаXDTO. Для файлов больше 50–100 МБ берите ЧтениеXML, для небольших документов со сложной вложенностью — DOM с XPath, для обмена по известной XSD-схеме — XDTO.

Все три механизма есть в платформе 8.3 и не зависят от конфигурации: код одинаково работает в Бухгалтерии, ЗУП, УТ или самописной базе. Чтобы не менять конфигурацию, загрузку обычно оформляют внешней обработкой: её пишут один раз и подключают к любой базе.

Чем разобрать XML в 1С: три инструмента и как выбрать

Во всех примерах разбираем один и тот же файл — прайс поставщика:

<?xml version="1.0" encoding="UTF-8"?>
<Catalog date="2026-10-01">
  <Item id="A-001">
    <Name>Бумага А4, 500 листов</Name>
    <Price>450.00</Price>
    <Qty>120</Qty>
  </Item>
  <Item id="A-002">
    <Name>Папка-регистратор</Name>
    <Price>189.50</Price>
    <Qty>40</Qty>
  </Item>
</Catalog>

Базовые объекты платформы для работы с XML:

ОбъектКак читаетПамятьКогда брать
ЧтениеXMLУзел за узлом, вперёдПочти не расходуетБольшие файлы, простая плоская структура
ПостроительDOM + ДокументDOMВесь файл в деревоРастёт с размером файлаНебольшие файлы, нужен произвольный доступ и XPath
ФабрикаXDTOВ объекты со свойствамиЗависит от способаЕсть XSD-схема, обмен с внешней системой
СериализаторXDTOВ объекты самой 1СЗависит от размераФайл выгружен из 1С через ЗаписатьXML

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

💡 Комбинировать можно: идти по файлу потоково и отдельные фрагменты превращать в XDTO-объекты. Этот приём разобран в разделе про производительность.

Подготовка: где выполнять парсинг и как собрать внешнюю обработку

Разбор XML выполняйте на сервере. Там доступны транзакции, запись в базу и нет ограничений тонкого и веб-клиента на работу с файлами.

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

  1. На клиенте вызовите НачатьПомещениеФайла (или ПоместитьФайл в старых формах) — файл попадёт во временное хранилище, вы получите адрес.
  2. Передайте адрес в серверную процедуру.
  3. На сервере получите двоичные данные: ПолучитьИзВременногоХранилища(Адрес).
  4. Запишите их во временный файл и откройте его объектом ЧтениеXML.
&НаСервере
Процедура ЗагрузитьНаСервере(АдресФайла)
    ДанныеФайла = ПолучитьИзВременногоХранилища(АдресФайла);
    ИмяФайла = ПолучитьИмяВременногоФайла("xml");
    ДанныеФайла.Записать(ИмяФайла);
    Попытка
        Товары = ПрочитатьТовары(ИмяФайла);
        // ... запись в базу
    Исключение
        УдалитьФайлы(ИмяФайла);
        ВызватьИсключение;
    КонецПопытки;
    УдалитьФайлы(ИмяФайла);
КонецПроцедуры

Небольшую XML-строку, полученную, например, из HTTP-ответа, писать в файл не нужно: у ЧтениеXML есть метод УстановитьСтроку(Строка).

Внешняя обработка для загрузки

Чтобы не трогать конфигурацию, код удобно держать во внешней обработке:

  1. В Конфигураторе: Файл → Новый → Внешняя обработка.
  2. Добавьте форму, на ней — поле выбора файла и кнопку «Загрузить».
  3. В модуле формы разместите клиентский выбор файла и серверную процедуру, как в примере выше.
  4. Сохраните файл с расширением .epf.

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

В типовых конфигурациях на БСП обработку лучше зарегистрировать: Администрирование → Печатные формы, отчеты и обработки → Дополнительные отчеты и обработки. Тогда её запускают без прав на открытие произвольных файлов.

Потоковый парсинг XML через ЧтениеXML

ЧтениеXML двигается по файлу методом Прочитать(). Каждый вызов переводит курсор на следующий узел и возвращает Ложь, когда файл закончился. Тип текущего узла — в свойстве ТипУзла.

Узлы, которые встречаются чаще всего:

  • 🟢 ТипУзлаXML.НачалоЭлемента — открывающий тег, тут доступны имя и атрибуты;
  • 📝 ТипУзлаXML.Текст — содержимое элемента, значение в свойстве Значение;
  • 🔴 ТипУзлаXML.КонецЭлемента — закрывающий тег.

Функция, которая читает прайс в массив структур:

Функция ПрочитатьТовары(ИмяФайла)
    Товары = Новый Массив;
    Чтение = Новый ЧтениеXML;
    Чтение.ОткрытьФайл(ИмяФайла);

    Текущий = Неопределено;
    ИмяПоля = "";

    Пока Чтение.Прочитать() Цикл
        Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
            Если Чтение.ЛокальноеИмя = "Item" Тогда
                Текущий = Новый Структура("Код, Наименование, Цена, Количество",
                    Чтение.ПолучитьАтрибут("id"), "", 0, 0);
            ИначеЕсли Текущий <> Неопределено Тогда
                ИмяПоля = Чтение.ЛокальноеИмя;
            КонецЕсли;

        ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.Текст И Текущий <> Неопределено Тогда
            Если ИмяПоля = "Name" Тогда
                Текущий.Наименование = Чтение.Значение;
            ИначеЕсли ИмяПоля = "Price" Тогда
                Текущий.Цена = XMLЗначение(Тип("Число"), Чтение.Значение);
            ИначеЕсли ИмяПоля = "Qty" Тогда
                Текущий.Количество = XMLЗначение(Тип("Число"), Чтение.Значение);
            КонецЕсли;

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

    Чтение.Закрыть();
    Возврат Товары;
КонецФункции

На нашем файле функция вернёт массив из двух структур. У второй: код A-002, цена 189,5, количество 40.

Что здесь важно:

  • ПолучитьАтрибут("id") возвращает Неопределено, если атрибута нет. Ошибки не будет — проверяйте значение сами.
  • Значение — всегда строка. Числа, даты и булевы приводите через XMLЗначение(Тип(...), Строка). Функция понимает каноническую запись XML: 450.00, 2026-10-01T00:00:00, true.
  • ЛокальноеИмя — имя без префикса пространства имён. Имя вернёт ns:Item, и сравнение с "Item" не сработает.
  • Ненужную ветку дерева можно перескочить методом Пропустить(), стоя на её открывающем теге.

Перебрать все атрибуты элемента, не зная их имён, можно парой ПервыйАтрибут() / СледующийАтрибут(): каждый вызов возвращает Истина, пока атрибуты есть, а имя и значение берутся из тех же Имя и Значение.

Разбор XML через DOM и поиск узлов по XPath

DOM загружает весь документ в память и даёт доступ к любому узлу в любом порядке. Код становится короче, но файл на 500 МБ так читать нельзя: дерево займёт в памяти в несколько раз больше исходного размера.

Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ИмяФайла);
Построитель = Новый ПостроительDOM;
Документ = Построитель.Прочитать(Чтение);
Чтение.Закрыть();

Узлы = Документ.ПолучитьЭлементыПоИмени("Item");
Для Индекс = 0 По Узлы.Количество() - 1 Цикл
    Узел = Узлы.Элемент(Индекс);
    Код = Узел.ПолучитьАтрибут("id");
    Имена = Узел.ПолучитьЭлементыПоИмени("Name");
    Наименование = ?(Имена.Количество() > 0, Имена.Элемент(0).ТекстовоеСодержимое, "");
КонецЦикла;

ТекстовоеСодержимое возвращает текст элемента вместе с текстом всех вложенных узлов. Для листового элемента вроде <Name> это ровно его значение.

Выборка через XPath

XPath избавляет от ручного обхода. Найдём товары дороже 300 рублей:

Разыменователь = Документ.СоздатьРазыменовательПИ();
Результат = Документ.ВычислитьВыражениеXPath("//Item[Price > 300]",
    Документ, Разыменователь, ТипРезультатаDOMXPath.УпорядоченныйИтераторУзлов);

Узел = Результат.ПолучитьСледующий();
Пока Узел <> Неопределено Цикл
    Сообщить(Узел.ПолучитьАтрибут("id"));
    Узел = Результат.ПолучитьСледующий();
КонецЦикла;

На нашем примере выведется только A-001: у второй позиции цена 189,50.

Если в корне файла объявлено пространство имён по умолчанию (xmlns="http://..."), выражение //Item ничего не найдёт. Задайте префикс через объект РазыменовательПространствИменDOM и пишите //ns:Item.

XDTO: чтение XML в типизированные объекты

XDTO превращает XML в объект, у которого элементы и атрибуты становятся свойствами. Это самый удобный путь, когда структура известна заранее.

Без схемы

Глобальная фабрика умеет читать произвольный XML:

Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ИмяФайла);
Каталог = ФабрикаXDTO.ПрочитатьXML(Чтение);
Чтение.Закрыть();

ДатаПрайса = Каталог.date;
Позиции = Каталог.Item;

Главная ловушка нетипизированного XDTO — повторяющиеся элементы. Если <Item> в файле два и больше, свойство вернёт СписокXDTO. Если ровно один — сразу ОбъектXDTO, и цикл Для Каждого по нему сломается. Приводите к списку явно:

Если ТипЗнч(Позиции) = Тип("ОбъектXDTO") Тогда
    Массив = Новый Массив;
    Массив.Добавить(Позиции);
    Позиции = Массив;
КонецЕсли;

Для Каждого Позиция Из Позиции Цикл
    Цена = XMLЗначение(Тип("Число"), Позиция.Price);
КонецЦикла;

Без схемы значения листовых элементов приходят строками, поэтому XMLЗначение по-прежнему нужен.

По XSD-схеме

Если внешняя система дала XSD, постройте фабрику из неё — тогда типы приходят сразу правильные, а файл проверяется на соответствие схеме:

Фабрика = СоздатьФабрикуXDTO("C:\exchange\catalog.xsd");
ТипКаталога = Фабрика.Тип("http://example.com/catalog", "Catalog");

Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ИмяФайла);
Каталог = Фабрика.ПрочитатьXML(Чтение, ТипКаталога);
Чтение.Закрыть();

Первый параметр Тип() — пространство имён схемы (targetNamespace), второй — имя типа. Для постоянного обмена схему удобнее импортировать в конфигурацию как XDTO-пакет: Общие → XDTO-пакеты, тогда фабрику создавать не нужно.

Отдельный случай — файл, выгруженный из самой 1С методом ЗаписатьXML. Его читают через СериализаторXDTO.ПрочитатьXML(Чтение): в ответ придёт готовый объект 1С (элемент справочника, документ), его останется записать.

Обработка ошибок и некорректной структуры XML-файла

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

Синтаксические — файл не является корректным XML: не закрыт тег, в тексте стоит голый &, кодировка в заголовке не совпадает с реальной. ЧтениеXML выбросит исключение в тот момент, когда дойдёт до сбойного места. Всё, что было прочитано до него, уже в памяти — решите, записывать ли частичный результат.

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

Попытка
    Товары = ПрочитатьТовары(ИмяФайла);
Исключение
    ТекстОшибки = ОписаниеОшибки();
    ЗаписьЖурналаРегистрации("Загрузка прайса XML",
        УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);
    ВызватьИсключение "Файл не удалось разобрать: " + ТекстОшибки;
КонецПопытки;

Что проверять в логике:

  • ✅ имя корневого элемента — первым же узлом после Прочитать();
  • ✅ наличие ключевых полей у каждой записи (код, цена) — пустые складывайте в отдельный список «пропущено»;
  • ✅ преобразование значений — XMLЗначение на строке 450,00 выбросит исключение; оберните его в Попытка для каждого поля или нормализуйте строку заранее;
  • ✅ дубли кодов внутри одного файла — через Соответствие.

💡 Пишите в журнал регистрации номер записи и код позиции, на которой случился сбой. Сообщение «ошибка разбора» без контекста в большом файле ничего не даёт.

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

Как ускорить парсинг больших XML-файлов

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

  1. Только потоковое чтение. DOM и нетипизированное XDTO для всего файла сразу на таких объёмах приводят к нехватке памяти рабочего процесса.
  2. Фрагменты через XDTO. Идите по файлу ЧтениеXML, а каждую запись <Item> читайте фабрикой — код остаётся коротким, память не растёт:
Чтение.ОткрытьФайл(ИмяФайла);
Чтение.Прочитать(); // корень <Catalog>
Чтение.Прочитать(); // первый <Item>
Пока Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Цикл
    Позиция = ФабрикаXDTO.ПрочитатьXML(Чтение);
    // обработка Позиция.Name, Позиция.Price
КонецЦикла;

После ПрочитатьXML курсор уже стоит на следующем узле, поэтому Прочитать() в цикле не вызывается — иначе каждая вторая запись потеряется. Цикл закончится на закрывающем </Catalog>.

  1. Справочники — одним запросом. Не ищите номенклатуру по коду для каждой строки. Соберите все коды из файла, получите ссылки одним запросом и положите в Соответствие.
  2. Запись пакетами в транзакциях. Фиксируйте транзакцию каждые 500–1000 записей. Одна транзакция на весь файл держит блокировки и раздувает журнал СУБД, транзакция на каждую запись — медленная.
  3. Фоновое задание. Загрузку на 10+ минут запускайте в фоне, чтобы не упираться в таймаут сеанса и не блокировать пользователя.

Флаг ОбменДанными.Загрузка = Истина ускоряет запись, потому что отключает проверки и обработчики объекта. Но вместе с ними пропадают и заполнение реквизитов, и контроль. Включайте его, только если точно знаете, что делают обработчики этого объекта.

Перед загрузкой большого файла
Выполнено: 0 / 6

Частые проблемы при разборе XML и что с ними делать

Диагностика: выберите симптом

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

Можно ли распарсить XML в 1С без программирования?
Только если для вашего формата есть готовая загрузка: CommerceML, обмен через «Конвертацию данных», типовая загрузка банковских выписок. Произвольный XML без кода не загрузить — нужна хотя бы внешняя обработка.
Чем ЧтениеXML отличается от ПостроительDOM?
ЧтениеXML идёт по файлу один раз вперёд и почти не расходует память. ПостроительDOM строит дерево всего документа: удобно искать и возвращаться к узлам, но объём ограничен памятью.
Как прочитать XML из строки, а не из файла?
Создайте ЧтениеXML и вызовите УстановитьСтроку(ТекстXML). Дальше всё как с файлом — можно передавать в DOM или XDTO.
Как получить значение атрибута в XDTO?
Атрибут становится свойством объекта с тем же именем: Объект.id. Если имя совпадает с именем вложенного элемента, используйте схему — без неё такие случаи разбираются неоднозначно.
Почему СериализаторXDTO не читает файл от внешней системы?
СериализаторXDTO понимает только формат, в котором 1С сама выгружает свои объекты. Чужой XML читайте через ФабрикаXDTO, ЧтениеXML или DOM.