Чтение XML в 1С 8.3: потоковый разбор, дерево DOM и объекты XDTO с примерами кода

· 10 мин

Содержание

Прочитать XML файл в 1С проще всего объектом ЧтениеXML: открываете файл методом ОткрытьФайл(), в цикле вызываете Прочитать() и по свойствам ТипУзла, Имя и Значение забираете нужные данные. Если файл небольшой и нужна выборка по пути к тегу, удобнее построить дерево через ПостроительDOM. Если у формата есть XSD-схема или структура простая, ФабрикаXDTO.ПрочитатьXML() превратит документ в объект со свойствами за одну строку.

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

Какие объекты платформы читают XML и когда какой брать

В 8.3 для разбора XML есть три подхода. Они отличаются тем, сколько памяти занимают и насколько удобно добираться до данных.

СпособОбъектыКак читаетКогда брать
Потоковый (SAX-подобный)ЧтениеXMLУзел за узлом, в памяти только текущийБольшие файлы, выгрузки на десятки и сотни МБ
Дерево DOMПостроительDOM, ДокументDOM, XPathВесь файл в память целикомФайлы до нескольких МБ, сложные выборки
Объектный XDTOФабрикаXDTO, ОбъектXDTO, СписокXDTOВесь фрагмент в объект со свойствамиФорматы с XSD-схемой, простые структуры

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

💡 Сочетать способы можно и нужно. Типичный рабочий приём для больших файлов: идти по файлу через ЧтениеXML, а каждый повторяющийся блок читать в объект XDTO. Пример будет в разделе про оптимизацию.

Для примеров возьмём такой файл orders.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Заказы дата="2025-03-14T10:00:00">
  <Заказ номер="105" клиент="ООО Ромашка">
    <Товар код="A-01" количество="3">Бумага А4</Товар>
    <Товар код="B-17" количество="1">Картридж</Товар>
  </Заказ>
  <Заказ номер="106" клиент="ИП Петров">
    <Товар код="A-01" количество="10">Бумага А4</Товар>
  </Заказ>
</Заказы>

Пошаговое чтение XML файла через ЧтениеXML

Шаг 1. Откройте файл

Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл("C:\Обмен\orders.xml");

Кодировку указывать не нужно: платформа берёт её из пролога <?xml ... encoding="..."?>. Если пролога нет, файл читается как UTF-8.

Для XML, который пришёл строкой (ответ HTTP-сервиса, поле в базе), вместо ОткрытьФайл() используйте УстановитьСтроку(ТекстXML).

Шаг 2. Пройдите узлы в цикле

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

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

Запустите этот цикл один раз на новом файле. Он покажет реальный порядок узлов, и станет видно, где у формата текст, а где атрибуты.

Шаг 3. Заберите текст нужного тега

Частая ошибка новичков — брать Значение у начала элемента. Оно там пустое. Текст лежит в следующем узле, поэтому после НачалоЭлемента нужно прочитать ещё раз:

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

Проверка ТипУзла после второго Прочитать() нужна для пустых тегов вида <Товар/>: у них текстового узла нет, и вы сразу попадёте на конец элемента.

Шаг 4. Закройте файл

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

Без Закрыть() файл остаётся занят процессом 1С, и его не удастся удалить или перенести в архив до конца сеанса. Если чтение может упасть с исключением, ставьте Закрыть() и в ветку Исключение блока Попытка.

Атрибуты и вложенные теги: разбор структуры XML

Как прочитать атрибут

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

Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И Чтение.Имя = "Заказ" Тогда
    НомерЗаказа = Чтение.ЗначениеАтрибута("номер");
    Клиент      = Чтение.ЗначениеАтрибута("клиент");
КонецЕсли;

Если атрибута в теге нет, метод вернёт Неопределено. Проверяйте это перед преобразованием в число или дату.

Когда набор атрибутов заранее неизвестен, переберите их все:

Пока Чтение.ПрочитатьАтрибут() Цикл
    Сообщить(Чтение.Имя + " = " + Чтение.Значение);
КонецЦикла;

Как собрать вложенную структуру

В потоковом чтении нет «родителя» у узла. Контекст держите сами в переменных: запомнили текущий заказ на НачалоЭлемента тега Заказ, добавляете в него товары, закрываете на КонецЭлемента.

Полный пример: читаем orders.xml в таблицу значений «заказ — товар — количество».

Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Заказ");
Таблица.Колонки.Добавить("Клиент");
Таблица.Колонки.Добавить("Код");
Таблица.Колонки.Добавить("Товар");
Таблица.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));

Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл("C:\Обмен\orders.xml");

ТекущийЗаказ = "";
ТекущийКлиент = "";

Пока Чтение.Прочитать() Цикл
    Если Чтение.ТипУзла <> ТипУзлаXML.НачалоЭлемента Тогда
        Продолжить;
    КонецЕсли;

    Если Чтение.Имя = "Заказ" Тогда
        ТекущийЗаказ  = Чтение.ЗначениеАтрибута("номер");
        ТекущийКлиент = Чтение.ЗначениеАтрибута("клиент");

    ИначеЕсли Чтение.Имя = "Товар" Тогда
        Строка = Таблица.Добавить();
        Строка.Заказ      = ТекущийЗаказ;
        Строка.Клиент     = ТекущийКлиент;
        Строка.Код        = Чтение.ЗначениеАтрибута("код");
        Строка.Количество = XMLЗначение(Тип("Число"), Чтение.ЗначениеАтрибута("количество"));

        Чтение.Прочитать();
        Если Чтение.ТипУзла = ТипУзлаXML.Текст Тогда
            Строка.Товар = Чтение.Значение;
        КонецЕсли;
    КонецЕсли;
КонецЦикла;

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

На выходе три строки: две по заказу 105 и одна по заказу 106.

Преобразование типов

Всё, что приходит из XML, — строки. Для чисел, дат и булевых значений используйте XMLЗначение(): она понимает формат XML Schema, в отличие от Число() и Дата().

Что в файлеКак преобразовать
12.50XMLЗначение(Тип("Число"), Стр)
2025-03-14T10:00:00XMLЗначение(Тип("Дата"), Стр)
true / falseXMLЗначение(Тип("Булево"), Стр)

Если источник пишет даты по-русски (14.03.2025), XMLЗначение выдаст ошибку. Такие строки разбирайте вручную через СтрРазделить() и собирайте Дата(Год, Месяц, День).

Пространства имён

В файлах ФНС, банков и ЭДО у тегов часто есть префиксы: <ns2:Документ>. Свойство Имя вернёт имя вместе с префиксом, а префикс в разных выгрузках бывает разным. Сравнивайте по ЛокальноеИмя, а при необходимости проверяйте URIПространстваИмен.

DOM и XPath: выборка из XML по пути к тегу

Когда файл небольшой, а нужны точечные данные («все товары с кодом A-01», «атрибут третьего заказа»), дерево DOM экономит много строк кода.

Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл("C:\Обмен\orders.xml");

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

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

Для выборки по условию подключите XPath:

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

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

DOM держит весь документ в памяти, причём объём в разы больше размера файла на диске. Файл на 200 МБ легко исчерпает память рабочего процесса на сервере. Для таких объёмов DOM не используйте.

ТекстовоеСодержимое склеивает текст всех потомков. У тега <Заказ> из примера оно вернёт «Бумага А4Картридж» вместе с пробелами-переносами. Берите его только у «листовых» элементов.

Чтение XML через XDTO: файл сразу в объект

Без схемы

ФабрикаXDTO.ПрочитатьXML() без указания типа строит объект с динамической структурой. Имена вложенных тегов и атрибутов становятся свойствами:

Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл("C:\Обмен\orders.xml");
Корень = ФабрикаXDTO.ПрочитатьXML(Чтение);
Чтение.Закрыть();

Сообщить(Корень.дата);

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

С XSD-схемой

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

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

ТипЗаказы = ФабрикаXDTO.Тип("http://example.ru/orders", "Заказы");
Корень = ФабрикаXDTO.ПрочитатьXML(Чтение, ТипЗаказы);

Здесь http://example.ru/orders — пространство имён из вашей схемы, у вас оно будет своё.

Повторяющиеся теги: значение или СписокXDTO

Без схемы платформа не знает, может ли тег повторяться. Если в заказе один <Товар>, свойство Заказ.Товар — это сам объект. Если товаров два и больше — это СписокXDTO. Код, написанный по файлу с одним товаром, упадёт на следующем файле.

Приведите оба случая к списку небольшой функцией:

Функция КакМассив(Значение)
    Результат = Новый Массив;
    Если ТипЗнч(Значение) = Тип("СписокXDTO") Тогда
        Для Каждого Элемент Из Значение Цикл
            Результат.Добавить(Элемент);
        КонецЦикла;
    ИначеЕсли Значение <> Неопределено Тогда
        Результат.Добавить(Значение);
    КонецЕсли;
    Возврат Результат;
КонецФункции

Со схемой, где у элемента указано maxOccurs="unbounded", свойство всегда будет списком, и функция не нужна.

Ещё одна деталь: если у тега есть и атрибуты, и текст (как <Товар код="A-01">Бумага А4</Товар>), то при чтении без схемы текст лежит в служебном свойстве __content.

Большие XML файлы: память, скорость, файл на клиенте

Гибрид: поток плюс XDTO по частям

Для выгрузки на 300 МБ с десятками тысяч одинаковых блоков работает такая схема. ЧтениеXML идёт по файлу, а дойдя до начала нужного тега, отдаёт текущую позицию в ФабрикаXDTO.ПрочитатьXML(). Та читает только этот элемент и останавливается после его конца.

Пока Чтение.Прочитать() Цикл
    Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И Чтение.ЛокальноеИмя = "Заказ" Тогда
        Заказ = ФабрикаXDTO.ПрочитатьXML(Чтение);
        ОбработатьЗаказ(Заказ);
    КонецЕсли;
КонецЦикла;

В памяти одновременно только один заказ. Удобство объектного доступа сохраняется.

Если пропустить ненужную ветку целиком, вызовите Чтение.Пропустить() на её начале: курсор перейдёт за её конец, не разбирая содержимое.

Запись в базу порциями

Медленнее всего обычно не разбор, а запись объектов. Что помогает:

  • 📦 Группируйте записи в транзакции по 500–1000 объектов, а не по одной и не всё в одной огромной транзакции.
  • 🔍 Справочники для поиска (номенклатура по коду, контрагенты по ИНН) загрузите заранее одним запросом в Соответствие, а не ищите НайтиПоКоду на каждой строке.
  • 🧾 Для регистров сведений пишите наборы записей, а не по записи.
  • 🖥 Тяжёлую загрузку запускайте на сервере или фоновым заданием, а не в клиентском модуле формы.

Файл выбран пользователем: передача на сервер

ЧтениеXML.ОткрытьФайл() открывает файл там, где выполняется код. В клиент-серверной базе путь C:\Users\... с компьютера пользователя на сервере не существует. Порядок такой:

  1. На клиенте пользователь выбирает файл, и его содержимое помещается во временное хранилище (НачатьПомещениеФайлаНаСервер() в актуальных платформах или ПоместитьФайл() в старых конфигурациях).
  2. На сервере получите данные: ДвоичныеДанные = ПолучитьИзВременногоХранилища(Адрес).
  3. Сохраните их во временный файл и откройте его:
ИмяФайла = ПолучитьИмяВременногоФайла("xml");
ДвоичныеДанные.Записать(ИмяФайла);

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

УдалитьФайлы(ИмяФайла);

Удалять временный файл нужно после Закрыть(), иначе он будет занят.

Ошибки при чтении XML в 1С и что с ними делать

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

💡 Перед загрузкой в рабочую базу прогоните обработку на копии. Одна ошибка в сопоставлении полей создаёт сотни лишних элементов справочников, и чистить их дольше, чем писать загрузку.

Частые вопросы о чтении XML в 1С

Можно ли открыть XML файл в 1С без программирования?
Посмотреть содержимое удобнее в браузере или текстовом редакторе. Загрузить данные в справочники и документы без кода получится, только если файл в формате, который понимает встроенная в конфигурацию обработка обмена (например, формат EnterpriseData).
Чем ЧтениеXML отличается от ПрочитатьXML?
ЧтениеXML — объект для разбора любого XML. Глобальная функция ПрочитатьXML() восстанавливает объекты 1С из XML, который был записан функцией ЗаписатьXML(). Для чужих форматов она не подходит.
Как проверить XML по XSD-схеме до загрузки?
Прочитайте файл через ФабрикаXDTO.ПрочитатьXML() с типом из схемы, обернув вызов в Попытка. Файл, не соответствующий схеме, вызовет исключение с описанием проблемы.
Как прочитать XML из ZIP-архива?
Распакуйте архив во временный каталог объектом ЧтениеZipФайла (метод ИзвлечьВсе()), затем откройте XML как обычный файл. После обработки удалите временный каталог.
Работает ли ЧтениеXML в веб-клиенте?
Разбор XML выполняйте на сервере. Файл пользователя передавайте через временное хранилище, как описано в разделе про большие файлы.