Чтение XML в 1С: потоковый разбор, DOM и XDTO
Содержание
Чтобы прочитать XML в 1С, в большинстве случаев берут объект ЧтениеXML: он открывает файл или строку и выдаёт содержимое узел за узлом, не загружая всё в память. Для файлов с заранее известной структурой удобнее DOM (ПостроительDOM + ДокументDOM), а для обмена по схеме — типизированное чтение через ФабрикаXDTO.
Ниже — три рабочих подхода к разбору XML на встроенном языке, примеры кода, работа с атрибутами, пространствами имён и XSD-схемами, плюс разбор ошибок, на которые натыкаются чаще всего. Весь код работает на платформе 1С:Предприятие 8.3.
Три способа разобрать XML и когда какой брать
В платформе нет «одного правильного» объекта для XML — есть три инструмента под разные задачи. Выбор зависит от размера файла и от того, знаете ли вы его структуру заранее.
- 📄 Потоковое чтение —
ЧтениеXML. Читает файл последовательно, узел за узлом, в одном направлении. Память почти не расходует. Подходит для больших файлов и для случаев, когда структура плавает. - 🌳 DOM —
ПостроительDOMиДокументDOM. Загружает весь документ в память в виде дерева. Удобно обращаться к любому узлу, искать по XPath. Платёж за удобство — оперативная память. - 🧩 XDTO —
ФабрикаXDTO. Разбирает XML в типизированные объекты по XSD-схеме. Нужен, когда есть формализованная схема обмена (ЕГАИС, ФНС, банковские выписки, обмен между конфигурациями).
| Способ | Память | Когда брать |
|---|---|---|
ЧтениеXML | минимум | большие файлы, простой обход, экспорт логов |
| DOM | весь файл | небольшие файлы, выборка по XPath, правка узлов |
| XDTO | весь объект | обмен по XSD-схеме, строгая типизация |
Если файл весит десятки или сотни мегабайт — забудьте про DOM и XDTO-чтение целиком. Только потоковое чтение ЧтениемXML.
Потоковое чтение: разбираем файл узел за узлом
Базовый сценарий. Создаём объект, открываем источник, крутим цикл по узлам и смотрим тип текущего узла.
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл("C:\Обмен\data.xml");
Пока Чтение.Прочитать() Цикл
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
Сообщить("Открыт элемент: " + Чтение.Имя);
ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.Текст Тогда
Сообщить("Текст: " + Чтение.Значение);
ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
Сообщить("Закрыт элемент: " + Чтение.Имя);
КонецЕсли;
КонецЦикла;
Чтение.Закрыть();
Метод Прочитать() сдвигает курсор на следующий узел и возвращает Ложь, когда узлы закончились. На этом держится весь цикл.
Ключевые свойства текущего узла:
ТипУзла— что сейчас под курсором (НачалоЭлемента,КонецЭлемента,Текст,Комментарийи т. д.).Имя— имя элемента или атрибута.Значение— текстовое содержимое узла.
Если источник — не файл, а строка (например, пришла из HTTP-ответа), открывают её напрямую:
Чтение = Новый ЧтениеXML;
Чтение.УстановитьСтроку(ТекстОтвета);
Всегда закрывайте объект методом Закрыть(). Пока файл открыт ЧтениемXML, он занят процессом 1С, и повторная запись в него упадёт с ошибкой доступа.
Если целый элемент не нужен (например, пропускаете служебный блок), не крутите по нему цикл вручную — перешагните его одним вызовом ПропуститьЭлемент(). Курсор встанет сразу за закрывающим тегом, и дальше цикл пойдёт как обычно.
Разберём типовую задачу целиком: прочитать список товаров из файла и сложить их в таблицу значений. Структура файла — элементы <Товар> с атрибутами Код и Наименование и вложенным элементом <Цена>.
Товары = Новый ТаблицаЗначений;
Товары.Колонки.Добавить("Код");
Товары.Колонки.Добавить("Наименование");
Товары.Колонки.Добавить("Цена");
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл("C:\Обмен\tovary.xml");
Строка = Неопределено;
ТекущийТег = "";
Пока Чтение.Прочитать() Цикл
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
ТекущийТег = Чтение.ЛокальноеИмя;
Если ТекущийТег = "Товар" Тогда
Строка = Товары.Добавить();
Строка.Код = Чтение.ЗначениеАтрибута("Код");
Строка.Наименование = Чтение.ЗначениеАтрибута("Наименование");
КонецЕсли;
ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.Текст И ТекущийТег = "Цена" Тогда
Строка.Цена = Число(Чтение.Значение);
КонецЕсли;
КонецЦикла;
Чтение.Закрыть();
На выходе — заполненная ТаблицаЗначений, готовая к записи в регистр, документ или к сверке. Этот каркас (поймать начало нужного элемента → забрать атрибуты → поймать текст вложенного узла) закрывает большинство реальных обменов.
Как читать атрибуты и текст внутри элементов
Атрибуты узла не попадают в общий цикл Прочитать() — их перебирают отдельно. Когда курсор стоит на начале элемента, пробегают по атрибутам методом ПрочитатьАтрибут():
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
ИмяЭлемента = Чтение.Имя;
Пока Чтение.ПрочитатьАтрибут() Цикл
Сообщить(ИмяЭлемента + "." + Чтение.Имя + " = " + Чтение.Значение);
КонецЦикла;
КонецЕсли;
Если известно имя конкретного атрибута, значение берут напрямую, не перебирая все:
Код = Чтение.ЗначениеАтрибута("Код");
Текст между открывающим и закрывающим тегами приходит отдельным узлом с типом ТипУзлаXML.Текст. Типовой приём — запомнить имя открытого элемента, на следующем шаге цикла забрать его текст:
ТекущийТег = "";
Пока Чтение.Прочитать() Цикл
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
ТекущийТег = Чтение.Имя;
ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.Текст Тогда
Если ТекущийТег = "Сумма" Тогда
Сумма = Число(Чтение.Значение);
КонецЕсли;
КонецЕсли;
КонецЦикла;
Значения из XML приходят строками. Числа и даты нужно явно приводить (Число(), Дата()), а дату из ISO-формата 2026-10-07T12:00:00 — через XMLЗначение(Тип("Дата"), Чтение.Значение), иначе рискуете получить ошибку преобразования.
Чтение через DOM, когда нужен произвольный доступ к узлам
DOM загружает документ целиком и даёт дерево, по которому можно ходить в любую сторону и делать выборки. Строят дерево из того же ЧтенияXML:
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл("C:\Обмен\data.xml");
Построитель = Новый ПостроительDOM;
ДокументDOM = Построитель.Прочитать(ЧтениеXML);
ЧтениеXML.Закрыть();
Дальше обращаются к элементам по имени:
Элементы = ДокументDOM.ПолучитьЭлементыПоИмени("Товар");
Для Каждого Элемент Из Элементы Цикл
Сообщить(Элемент.ТекстовоеСодержимое);
КонецЦикла;
Для сложной выборки удобнее XPath — он вычисляется методом ВычислитьВыражениеXPath. Если в документе есть пространства имён, XPath без разыменователя работать не будет (об этом ниже).
Главное ограничение DOM — память. Дерево держит в оперативке весь файл плюс накладные расходы на объекты узлов. Для файла в несколько мегабайт это нормально, для сотен мегабайт — путь к Недостаточно памяти.
Типизированное чтение по XSD-схеме через XDTO
Когда у обмена есть XSD-схема, разбирать XML вручную не нужно — платформа сама соберёт типизированные объекты. Сначала загружают схему и строят по ней фабрику:
ЧтениеСхемы = Новый ЧтениеXML;
ЧтениеСхемы.ОткрытьФайл("C:\Обмен\scheme.xsd");
НаборСхем = ФабрикаXDTO.ПрочитатьНаборСхемXML(ЧтениеСхемы);
ЧтениеСхемы.Закрыть();
Фабрика = Новый ФабрикаXDTO(НаборСхем);
Затем читают данные этой фабрикой:
ЧтениеДанных = Новый ЧтениеXML;
ЧтениеДанных.ОткрытьФайл("C:\Обмен\data.xml");
Объект = Фабрика.ПрочитатьXML(ЧтениеДанных);
ЧтениеДанных.Закрыть();
Сообщить(Объект.Номер);
Сообщить(Объект.Дата);
К свойствам полученного объекта обращаются по именам из схемы — платформа уже привела типы (число останется числом, дата — датой).
Если XML — это сериализованный прикладной объект 1С (документ, элемент справочника, выгруженный ЗаписатьXML), его читают глобальной фабрикой и СериализаторомXDTO:
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(Путь);
Если ВозможностьЧтенияXML(ЧтениеXML) Тогда
Значение = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
КонецЕсли;
ЧтениеXML.Закрыть();
Если точный тип XDTO заранее неизвестен, вызывайте ПрочитатьXML без указания типа — платформа определит его по содержимому файла и схеме.
Пространства имён: почему элементы «не находятся»
Самая частая засада при чтении обменных файлов — пространства имён (namespaces). Элемент в файле выглядит как <ns:Товар> или объявлен через xmlns="http://...", и поиск по короткому имени "Товар" ничего не возвращает.
При потоковом чтении имя делится на две части:
Чтение.Имя— имя с префиксом, как в файле (ns:Товар).Чтение.ЛокальноеИмя— имя без префикса (Товар).Чтение.URIПространстваИмен— URI пространства, к которому относится узел.
Сравнивайте элементы по ЛокальноеИмя и по URI пространства, а не по полному имени с префиксом — префикс в файле может быть любым, а URI постоянен.
Для XPath в DOM нужен разыменователь пространств имён — он сопоставляет префиксы из вашего выражения с URI документа:
Разыменователь = ДокументDOM.СоздатьРазыменовательПространствИмен();
Результат = ДокументDOM.ВычислитьВыражениеXPath(
"//d:Товар", ДокументDOM, Разыменователь);
Без разыменователя XPath по файлу с namespace вернёт пустоту, хотя данные в файле есть.
Частые ошибки при чтении XML и как их обойти
Разбор чужого XML почти всегда упирается в данные, а не в код. Вот типовые симптомы и причины.
encoding="UTF-8", а файл реально в Windows-1251 (или наоборот). Приведите фактическую кодировку файла к объявленной либо исправьте объявление.ЛокальноеИмя + URI, а для XPath задайте разыменователь пространств имён.ЧтениемXML без загрузки всего дерева.ЧтениеXML не закрыт методом Закрыть(), файл остался занят. Закрывайте объект сразу после разбора, лучше в блоке Попытка … Исключение.Чтобы не ловить незакрытый файл при исключении, оборачивайте чтение в Попытка:
Чтение = Новый ЧтениеXML;
Попытка
Чтение.ОткрытьФайл(Путь);
// разбор
Исключение
Сообщить(ОписаниеОшибки());
КонецПопытки;
Чтение.Закрыть();
Оптимизация: как читать большие XML без тормозов
Разница между подходами на большом файле — не в скорости, а в том, запустится код вообще или упадёт по памяти. Несколько правил, которые держат разбор лёгким.
- ⚡ Только потоковое чтение. Для файлов от нескольких мегабайт —
ЧтениеXMLи обход в цикле. DOM и чтение всего объекта XDTO исключаем. - 🧹 Не копите данные в памяти. Обработали узел (записали в таблицу значений, в регистр, в файл) — не держите его. Иначе смысл потокового чтения теряется.
- 📦 Пишите пачками. Если по ходу разбора пишете в базу, накапливайте строки и проводите транзакцией по N записей, а не по одной.
- 🧵 Читайте из потока. Если файл приходит из архива или по сети, открывайте
ЧтениемXMLпоток напрямую — не выгружайте весь файл на диск ради чтения. - 🚫 Не логируйте каждый узел.
Сообщить()в цикле на миллионах узлов сам по себе тормозит сильнее разбора. Логируйте итог или каждую N-ю запись.
Полезный приём для огромных однотипных файлов — «перемотка»: доходите потоковым чтением до нужного крупного элемента, а уже его небольшое поддерево при необходимости читаете через ПрочитатьФрагмент или собираете локальный DOM из этого куска.
Проверьте, что ваш разбор готов к боевому файлу:
Частые вопросы
Чем `ЧтениеXML` отличается от `ПостроителяDOM`?
ЧтениеXML читает файл потоком, узел за узлом, и почти не тратит память — но ходить можно только вперёд. ПостроительDOM загружает весь документ в память в виде дерева: доступ к любому узлу и XPath, но за счёт оперативки. Поток — для больших файлов, DOM — для небольших с произвольной выборкой.Как прочитать XML из строки, а не из файла?
ЧтениеXML и вызовите УстановитьСтроку(ТекстXML) вместо ОткрытьФайл. Дальше разбор идёт тем же циклом Прочитать(). Удобно для XML, пришедшего в HTTP-ответе.Почему элемент не находится, хотя в файле он есть?
ЛокальноеИмя и сверяйте URIПространстваИмен, а не по полному имени с префиксом. Для XPath задайте разыменователь пространств имён, иначе выборка вернёт пусто.Как привести значение из XML к числу или дате?
Значение и всегда приходит строкой. Число — через Число(), дату в ISO-формате — через XMLЗначение(Тип("Дата"), Чтение.Значение). Прямое Дата() на строке вида 2026-10-07T00:00:00 сработает не всегда.Нужна ли XSD-схема, чтобы прочитать XML?
Как не словить «нет доступа к файлу» после чтения?
Закрыть() сразу после разбора и делайте это даже при ошибке — внутри Попытка … Исключение. Пока файл открыт ЧтениемXML, он занят процессом, и повторный доступ к нему упадёт.