Чтение XML в 1С 8.3: потоковый разбор, дерево DOM и объекты XDTO с примерами кода
Содержание
Прочитать 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.50 | XMLЗначение(Тип("Число"), Стр) |
2025-03-14T10:00:00 | XMLЗначение(Тип("Дата"), Стр) |
true / false | XMLЗначение(Тип("Булево"), Стр) |
Если источник пишет даты по-русски (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\... с компьютера пользователя на сервере не существует. Порядок такой:
- На клиенте пользователь выбирает файл, и его содержимое помещается во временное хранилище (
НачатьПомещениеФайлаНаСервер()в актуальных платформах илиПоместитьФайл()в старых конфигурациях). - На сервере получите данные:
ДвоичныеДанные = ПолучитьИзВременногоХранилища(Адрес). - Сохраните их во временный файл и откройте его:
ИмяФайла = ПолучитьИмяВременногоФайла("xml");
ДвоичныеДанные.Записать(ИмяФайла);
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ИмяФайла);
// ... разбор ...
Чтение.Закрыть();
УдалитьФайлы(ИмяФайла);
Удалять временный файл нужно после Закрыть(), иначе он будет занят.
Ошибки при чтении XML в 1С и что с ними делать
💡 Перед загрузкой в рабочую базу прогоните обработку на копии. Одна ошибка в сопоставлении полей создаёт сотни лишних элементов справочников, и чистить их дольше, чем писать загрузку.
Частые вопросы о чтении XML в 1С
Можно ли открыть XML файл в 1С без программирования?
Чем ЧтениеXML отличается от ПрочитатьXML?
ЧтениеXML — объект для разбора любого XML. Глобальная функция ПрочитатьXML() восстанавливает объекты 1С из XML, который был записан функцией ЗаписатьXML(). Для чужих форматов она не подходит.Как проверить XML по XSD-схеме до загрузки?
ФабрикаXDTO.ПрочитатьXML() с типом из схемы, обернув вызов в Попытка. Файл, не соответствующий схеме, вызовет исключение с описанием проблемы.Как прочитать XML из ZIP-архива?
ЧтениеZipФайла (метод ИзвлечьВсе()), затем откройте XML как обычный файл. После обработки удалите временный каталог.