Чтение XML в 1С:Предприятии 8.3 — от готовой обработки до XDTO
Содержание
Прочитать XML-файл в 1С 8.3 можно четырьмя способами. Если файл выгружен из такой же базы, его загружают готовой обработкой «Выгрузка и загрузка данных XML». Если файл чужой (прайс поставщика, ответ сервиса, выгрузка с сайта), его читают кодом: потоково через ЧтениеXML, деревом через ПостроительDOM или объектами через ФабрикаXDTO.
Типичная ситуация: поставщик раз в неделю присылает прайс в XML, и бухгалтер вручную переносит цены в 1С. Процедура на 40 строк кода делает то же за секунды. Ниже разобраны все варианты чтения — с кодом, который можно взять за основу, и с ловушками, на которых обычно спотыкаются.
Какой способ чтения XML выбрать
Способ зависит от двух вещей: откуда файл и насколько он большой. Сравнение в одной таблице:
| Способ | Когда подходит | Плюсы | Ограничения |
|---|---|---|---|
| Обработка «Выгрузка и загрузка данных XML» | Перенос данных между базами одной конфигурации | Без программирования | Чужие файлы не читает, структура метаданных должна совпадать |
ЧтениеXML | Большие файлы, простой разбор «по тегам» | Мало памяти, быстро | Код длиннее, нужно следить за вложенностью |
ПостроительDOM + XPath | Файлы до десятков мегабайт со сложной вложенностью | Можно искать узлы по пути и имени | Весь документ в памяти |
ФабрикаXDTO | Файлы со стабильной схемой, есть XSD | Обращение к данным как к свойствам объекта, проверка по схеме | Без схемы — сюрпризы с типами и списками |
Для всех программных способов один и тот же каркас: файл попадает на сервер, открывается объектом ЧтениеXML, а дальше вы либо читаете узлы сами, либо отдаёте поток построителю DOM или фабрике XDTO.
Загрузка XML готовой обработкой без программирования
Для переноса справочников и документов между двумя базами одной конфигурации используют универсальную внешнюю обработку «Выгрузка и загрузка данных XML». Для платформы 8.3 это файл ВыгрузкаЗагрузкаДанныхXML83.epf. Его распространяют с дисками ИТС и в комплекте поставки обработок для разработчиков.
Порядок работы:
- В базе-приёмнике откройте обработку через
Файл → Открыть. Нужны права на открытие внешних обработок; в типовых конфигурациях при первом открытии появится предупреждение защиты от опасных действий. - Перейдите на вкладку загрузки и укажите XML-файл, выгруженный этой же обработкой из базы-источника.
- Запустите загрузку и дождитесь сообщения об окончании.
Что важно знать до запуска:
- 🔑 Объекты загружаются со своими уникальными идентификаторами. Если в приёмнике уже есть элемент с тем же идентификатором, он будет перезаписан без вопросов.
- 🧩 Имена объектов метаданных в источнике и приёмнике должны совпадать. Выгрузку из Бухгалтерии в ЗУП так не перенести.
- 🚫 Запись идёт в режиме обмена данными: проверки заполнения и часть подписок на события не срабатывают. Документы после загрузки обычно нужно перепровести.
Перед загрузкой сделайте резервную копию базы-приёмника. Откатить перезаписанные элементы обработка не умеет.
Для обмена между разными конфигурациями служит обработка «Универсальный обмен данными в формате XML». Она читает файл по правилам конвертации, которые готовят в конфигурации «Конвертация данных». Без правил она бесполезна.
Чужой XML (прайс, заказ из интернет-магазина, ответ веб-сервиса) ни одна из этих обработок не прочитает. Для него нужен код — дальше разбираем, как его написать.
Как передать XML-файл с компьютера пользователя на сервер
Код разбора лучше выполнять на сервере: там нет ограничений тонкого и веб-клиента, а результат сразу можно записать в базу. Файл же лежит на компьютере пользователя. Поэтому сначала его помещают во временное хранилище:
&НаКлиенте
Процедура ЗагрузитьXML(Команда)
Оповещение = Новый ОписаниеОповещения("ПослеПомещенияФайла", ЭтотОбъект);
НачатьПомещениеФайла(Оповещение, , , Истина, УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ПослеПомещенияФайла(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт
Если Результат Тогда
ЗагрузитьНаСервере(Адрес);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ЗагрузитьНаСервере(Адрес)
ДвоичныеДанные = ПолучитьИзВременногоХранилища(Адрес);
ИмяФайла = ПолучитьИмяВременногоФайла("xml");
ДвоичныеДанные.Записать(ИмяФайла);
Товары = ПрочитатьТовары(ИмяФайла);
// ... запись данных в базу
УдалитьФайлы(ИмяФайла);
КонецПроцедуры
💡 Асинхронный вызов НачатьПомещениеФайла работает и в тонком клиенте, и в веб-клиенте. Модальные диалоги в современных конфигурациях часто запрещены свойством «Режим использования модальности», так что синхронные варианты лучше не применять.
Если файл уже лежит на сервере (например, его кладёт туда внешний сервис), шаг с хранилищем не нужен: путь сразу передают в ЧтениеXML.ОткрытьФайл(). Путь должен быть доступен пользователю, от имени которого работает сервер 1С, а не вашей учётной записи.
Потоковое чтение XML через объект ЧтениеXML
ЧтениеXML идёт по файлу узел за узлом. В каждый момент в памяти находится только текущий узел, поэтому так читаются и файлы на сотни мегабайт.
Возьмём простой прайс:
<?xml version="1.0" encoding="UTF-8"?>
<Товары>
<Товар Код="001">
<Наименование>Бумага А4</Наименование>
<Цена>350.00</Цена>
</Товар>
<Товар Код="002">
<Наименование>Папка-регистратор</Наименование>
<Цена>189.50</Цена>
</Товар>
</Товары>
Функция разбирает его в таблицу значений:
&НаСервереБезКонтекста
Функция ПрочитатьТовары(ИмяФайла)
Результат = Новый ТаблицаЗначений;
Результат.Колонки.Добавить("Код", Новый ОписаниеТипов("Строка"));
Результат.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));
Результат.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число"));
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ИмяФайла);
ТекущаяСтрока = Неопределено;
ТекущееПоле = "";
Пока Чтение.Прочитать() Цикл
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
Если Чтение.ЛокальноеИмя = "Товар" Тогда
ТекущаяСтрока = Результат.Добавить();
ТекущаяСтрока.Код = Чтение.ПолучитьАтрибут("Код");
ИначеЕсли ТекущаяСтрока <> Неопределено Тогда
ТекущееПоле = Чтение.ЛокальноеИмя;
КонецЕсли;
ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.Текст И ТекущаяСтрока <> Неопределено Тогда
Если ТекущееПоле = "Наименование" Тогда
ТекущаяСтрока.Наименование = Чтение.Значение;
ИначеЕсли ТекущееПоле = "Цена" Тогда
ТекущаяСтрока.Цена = XMLЗначение(Тип("Число"), Чтение.Значение);
КонецЕсли;
ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
Если Чтение.ЛокальноеИмя = "Товар" Тогда
ТекущаяСтрока = Неопределено;
КонецЕсли;
ТекущееПоле = "";
КонецЕсли;
КонецЦикла;
Чтение.Закрыть();
Возврат Результат;
КонецФункции
Как это работает:
Прочитать()переходит к следующему узлу и возвращаетЛожь, когда файл закончился.- На открывающем теге
<Товар>создаётся строка таблицы, атрибутКодберётся черезПолучитьАтрибут(). - Текст внутри
<Наименование>и<Цена>приходит отдельным узлом типаТекст— сразу после начала элемента. - На закрывающем
</Товар>строка «отпускается», чтобы случайный текст вне товара не попал в таблицу.
Пара приёмов, без которых код быстро ломается:
- 🏷️
ЛокальноеИмявместоИмя. Если в файле есть префиксы пространств имён (<ns1:Товар>), свойствоИмявернётns1:Товар, и сравнение не сработает. - 🔢
XMLЗначение()для чисел и дат. XML хранит число с точкой (350.00), дату — как2025-03-14T00:00:00. ФункцияXMLЗначение(Тип("Число"), ...)иXMLЗначение(Тип("Дата"), ...)преобразует их корректно, аЧисло("350.00")на сервере с русскими региональными настройками может упасть. - 📄 Чтение из строки. Если XML пришёл ответом HTTP-сервиса, файл не нужен:
Чтение.УстановитьСтроку(ТекстОтвета).
Разбор XML деревом: ПостроительDOM и XPath
Когда структура глубокая (документ → шапка → контрагент → адрес → индекс), отслеживать вложенность в потоковом цикле неудобно. Проще загрузить файл в дерево DOM и брать нужные узлы по имени или по пути:
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ИмяФайла);
Построитель = Новый ПостроительDOM;
Документ = Построитель.Прочитать(Чтение);
Чтение.Закрыть();
Узлы = Документ.ПолучитьЭлементыПоИмени("Товар");
Для Каждого Узел Из Узлы Цикл
Код = Узел.ПолучитьАтрибут("Код");
Наименование = Узел.ПолучитьЭлементыПоИмени("Наименование").Элемент(0).ТекстовоеСодержимое;
Цена = XMLЗначение(Тип("Число"),
Узел.ПолучитьЭлементыПоИмени("Цена").Элемент(0).ТекстовоеСодержимое);
КонецЦикла;
Для выборки по условию подходит XPath. Например, все товары дороже 200:
Разыменователь = Документ.СоздатьРазыменовательПИ();
Результат = Документ.ВычислитьВыражениеXPath("//Товар[Цена > 200]", Документ, Разыменователь);
Узел = Результат.ПолучитьСледующий();
Пока Узел <> Неопределено Цикл
Сообщить(Узел.ПолучитьАтрибут("Код"));
Узел = Результат.ПолучитьСледующий();
КонецЦикла;
DOM держит весь документ в памяти, причём объём в памяти заметно больше размера файла. На файле в несколько сотен мегабайт рабочий процесс сервера может упереться в память и оборвать сеансы других пользователей. Большие файлы читайте потоково.
💡 Если ПолучитьЭлементыПоИмени ничего не находит, а элементы в файле точно есть — скорее всего, у документа задано пространство имён по умолчанию (xmlns="..."). Тогда используйте вариант метода с URI пространства имён или выражение XPath с префиксом, который знает разыменователь.
Чтение XML через XDTO: объекты вместо тегов
XDTO превращает XML в объекты: к элементу обращаются как к свойству, без циклов по узлам. Есть два режима.
Без схемы (нетипизированное чтение)
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ИмяФайла);
Данные = ФабрикаXDTO.ПрочитатьXML(Чтение);
Чтение.Закрыть();
Список = Данные.Товар;
Если ТипЗнч(Список) = Тип("ОбъектXDTO") Тогда
// в файле один товар — оборачиваем, чтобы цикл работал одинаково
Массив = Новый Массив;
Массив.Добавить(Список);
Список = Массив;
КонецЕсли;
Для Каждого Товар Из Список Цикл
Код = Товар.Код;
Наименование = Товар.Наименование;
Цена = XMLЗначение(Тип("Число"), Товар.Цена);
КонецЦикла;
ПрочитатьXML возвращает корневой элемент, атрибуты и вложенные элементы доступны как свойства. Главная ловушка этого режима видна в коде: если товар в файле один, свойство вернёт ОбъектXDTO, если несколько — СписокXDTO. Код, написанный на тестовом файле с десятью товарами, падает на первом реальном файле с одним. Значения без схемы приходят строками, поэтому числа и даты всё равно преобразуют через XMLЗначение().
По схеме XSD (типизированное чтение)
Если у формата есть XSD-схема, её загружают в конфигурацию как XDTO-пакет:
- В Конфигураторе откройте ветку
Общие → XDTO-пакеты. - Вызовите контекстное меню и импортируйте XML-схему из файла
.xsd. - Посмотрите в свойствах пакета его пространство имён (URI) — оно понадобится в коде.
- Обновите конфигурацию базы данных.
Чтение по типу корневого элемента:
URI = "http://example.com/goods";
ТипКорня = ФабрикаXDTO.Тип(URI, "Товары");
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ИмяФайла);
Данные = ФабрикаXDTO.ПрочитатьXML(Чтение, ТипКорня);
Чтение.Закрыть();
Теперь Данные.Товар — всегда СписокXDTO, если схема допускает несколько элементов, а Цена приходит числом, если в схеме у неё числовой тип. Расплата за удобство — жёсткость: файл, не совпадающий со схемой, не прочитается.
Менять конфигурацию ради одной схемы не обязательно. Фабрику можно собрать из XSD прямо в коде: прочитать схему через ПостроительDOM, получить объект СхемаXML методом ПостроительСхемXML.СоздатьСхемуXML(), добавить его в НаборСхемXML и создать Новый ФабрикаXDTO(НаборСхем). Это удобно во внешней обработке, которую нельзя встраивать в типовую конфигурацию.
Проверка структуры XML и обработка ошибок чтения
Чужой файл обязательно когда-нибудь придёт битым: оборванным при передаче, в другой кодировке, с изменённой структурой. Код должен сообщить об этом понятно, а не упасть с системным окном.
Базовая защита — обернуть разбор в Попытка:
Попытка
Товары = ПрочитатьТовары(ИмяФайла);
Исключение
ТекстОшибки = ОписаниеОшибки();
ЗаписьЖурналаРегистрации("Загрузка прайса", УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);
ВызватьИсключение "Файл не является корректным XML или повреждён. " + ТекстОшибки;
КонецПопытки;
ЧтениеXML проверяет только правильность разметки: закрыты ли теги, корректны ли символы. Соответствие схеме он не проверяет. Для проверки по схеме читают файл через XDTO с типом и вызывают у результата Проверить() — метод выбросит исключение с описанием несоответствия.
Частые причины сбоев и что с ними делать:
<?xml ... encoding="..."?>, без неё считает файл UTF-8. Попросите отправителя указать кодировку в заголовке или прочитайте файл через ЧтениеТекста в нужной кодировке и передайте строку в УстановитьСтроку().350,00) или с пробелами-разделителями разрядов. XMLЗначение ждёт формат XML — с точкой. Нормализуйте строку через СтрЗаменить перед преобразованием.Имя, а в файле есть префикс пространства имён. Сравнивайте ЛокальноеИмя. Второй вариант: имя элемента в файле отличается регистром — XML к регистру чувствителен.ЧтениеXML не закрыт, и файл остался заблокирован. Вызывайте Закрыть(), в том числе в ветке Исключение.<?xml стоят пробелы, пустая строка или посторонний текст. Объявление XML должно быть в самом начале файла.Если файлы приходят регулярно, добавьте простую проверку содержимого после разбора: количество строк больше нуля, у каждой строки заполнен код, цена больше нуля. Запись в базу делайте только после того, как прошла вся проверка, — иначе битый файл оставит полузагруженный прайс.
Частые вопросы о чтении XML в 1С
Можно ли прочитать XML на клиенте, не передавая файл на сервер?
ЧтениеXML доступен и на клиенте. Но писать результат в базу всё равно придётся на сервере, а в веб-клиенте прямого доступа к файлам нет. Разбор на сервере проще и надёжнее.Чем глобальная функция ПрочитатьXML отличается от ФабрикаXDTO.ПрочитатьXML?
ПрочитатьXML читает значения, ранее записанные функцией ЗаписатьXML в формате сериализации 1С (ссылки, структуры, таблицы). Произвольный чужой XML ей не подходит — для него нужна фабрика XDTO.Как открыть XML-файл, чтобы просто посмотреть, что внутри?
Сколько весит XML, который ещё можно читать через DOM?
Как прочитать XML из архива ZIP?
ЧтениеZipФайла во временный каталог, затем читайте извлечённый XML как обычный файл и удалите временные файлы после разбора.