Решение задач 1С:Предприятие 8 на примерах

XML в 1С программно: запись, чтение, DOM и выгрузка данных

Интеграция и веб-сервисыОпубликовано

XML по-прежнему остаётся одним из главных форматов обмена: на нём построены обмены через EnterpriseData, электронные документы, выгрузки для банков и государственных сервисов. В статье — программная работа с XML в 1С 8.3: как сформировать документ через ЗаписьXML, как прочитать XML потоково и через DOM, как получить из XML структуру, как выгрузить справочник и что означает «Ошибка разбора XML».

Когда XML нужно обрабатывать программно

Слово «XML в 1С» означает для разных людей разное. Бухгалтеру обычно нужно загрузить готовый файл обмена — для этого в типовых конфигурациях есть встроенные обработки и механизмы синхронизации, и вопрос «как загрузить XML в 1С» решается через меню, без кода. Программист же сталкивается с XML формат в 1С, когда нужно сформировать файл по чужой схеме, разобрать ответ веб-сервиса или сделать нестандартную 1С выгрузку в XML. Об этом и пойдёт речь.

В платформе есть три подхода. ЗаписьXML и ЧтениеXML работают потоково — быстро и экономно. ПостроительDOM и ЗаписьDOM строят и сохраняют полное дерево документа. СериализаторXDTO и фабрика XDTO работают со схемами XSD и объектами конфигурации. Начнём с первого.

Запись XML: ЗаписьXML

Документ формируется последовательными вызовами: объявление, открытие элемента, атрибуты, текст, закрытие элемента. Каждому ЗаписатьНачалоЭлемента должен соответствовать свой ЗаписатьКонецЭлемента. Атрибуты записываются сразу после начала элемента, до любого вложенного содержимого.

Запись = Новый ЗаписьXML;
Параметры = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Истина);   // кодировка, версия, отступы
Запись.ОткрытьФайл("C:\Exchange\catalog.xml", Параметры);

Запись.ЗаписатьОбъявлениеXML();
Запись.ЗаписатьНачалоЭлемента("catalog");
Запись.ЗаписатьАтрибут("date", XMLСтрока(ТекущаяДатаСеанса()));

Запись.ЗаписатьНачалоЭлемента("item");
Запись.ЗаписатьАтрибут("id", "1");
	Запись.ЗаписатьНачалоЭлемента("name");
	Запись.ЗаписатьТекст("Болт М8 & гайка");   // & будет экранирован автоматически
	Запись.ЗаписатьКонецЭлемента();
	Запись.ЗаписатьНачалоЭлемента("price");
	Запись.ЗаписатьТекст(XMLСтрока(12.5));
	Запись.ЗаписатьКонецЭлемента();
Запись.ЗаписатьКонецЭлемента();   // item

Запись.ЗаписатьКонецЭлемента();   // catalog
Запись.Закрыть();

Числа и даты записывайте через XMLСтрока: она даёт формат, не зависящий от региональных настроек, — точка в качестве разделителя дробной части и дата вида 2026-10-31T14:05:00. Если записать число через Строка(), можно получить неразрывные пробелы между разрядами и запятую, и принимающая сторона не разберёт значение.

Строка XML 1С: запись в память

Чтобы получить строку XML для отправки в веб-сервис, вместо ОткрытьФайл вызовите УстановитьСтроку. Результат возвращает метод Закрыть.

Запись = Новый ЗаписьXML;
Запись.УстановитьСтроку("UTF-8");
Запись.ЗаписатьОбъявлениеXML();
Запись.ЗаписатьНачалоЭлемента("request");
Запись.ЗаписатьАтрибут("method", "getStatus");
Запись.ЗаписатьТекст("A-1024");
Запись.ЗаписатьКонецЭлемента();
ТекстXML = Запись.Закрыть();
// <?xml version="1.0" encoding="UTF-8"?><request method="getStatus">A-1024</request>

Чтение XML потоком: ЧтениеXML

Потоковое чтение — основной способ, когда нужно 1С прочитать XML большого размера. Объект проходит по документу узел за узлом в цикле Пока Чтение.Прочитать(). На каждом шаге свойство ТипУзла сообщает, что перед нами: начало элемента, текст или конец элемента; Имя — имя элемента; Значение — текст; метод ЗначениеАтрибута возвращает атрибут текущего элемента.

Функция ПрочитатьКаталог(ПутьКФайлу)

	Товары = Новый Массив;
	Текущий = Неопределено;
	ТекущееПоле = "";

	Чтение = Новый ЧтениеXML;
	Чтение.ОткрытьФайл(ПутьКФайлу);

	Пока Чтение.Прочитать() Цикл

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

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

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

	КонецЦикла;

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

КонецФункции

Обратная к XMLСтрока функция XMLЗначение превращает текст обратно в число, дату или булево. Если XML пришёл строкой, а не файлом, используйте Чтение.УстановитьСтроку(ТекстXML). Учтите, что при наличии пробелов и переносов между элементами парсер может выдавать узлы с пробельным текстом; в примере они безвредны, потому что текст присваивается только внутри известных полей.

DOM и XPath

Когда документ небольшой, а логика сложная — нужно искать узлы по условию, возвращаться назад, менять документ, — удобнее DOM. ПостроительDOM читает XML в объект ДокументDOM, по которому можно перемещаться и делать выборки XPath.

Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл("C:\Exchange\catalog.xml");
Построитель = Новый ПостроительDOM;
Документ = Построитель.Прочитать(Чтение);
Чтение.Закрыть();

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

// XPath: имя товара с id = 1
Разыменователь = Новый РазыменовательПространствИменDOM(Документ);
Результат = Документ.ВычислитьВыражениеXPath("/catalog/item[@id='1']/name", Документ,
	Разыменователь, ТипРезультатаDOMXPath.УпорядоченныйИтераторУзлов);
Узел = Результат.ПолучитьСледующий();
Пока Узел <> Неопределено Цикл
	Сообщить(Узел.ТекстовоеСодержимое);
	Узел = Результат.ПолучитьСледующий();
КонецЦикла;

Если в документе объявлено пространство имён по умолчанию (атрибут xmlns у корня), простое выражение вида /catalog/item ничего не найдёт: узлы принадлежат пространству имён. В этом случае создают разыменователь с явным соответствием префикса и URI и используют префикс в выражении. Сохранить изменённый документ можно объектом ЗаписьDOM: создайте его и вызовите ЗаписьDOM.Записать(Документ, ЗаписьXML), передав подготовленный объект ЗаписьXML с открытым файлом или строкой.

1С XML в структуру: рекурсивная функция

Для небольших ответов сервисов удобно один раз превратить XML в коллекции 1С и дальше работать с ними как с JSON. Функция ниже обходит дерево DOM рекурсивно: элемент без дочерних элементов становится строкой, элемент с дочерними — соответствием, повторяющиеся имена собираются в массив. Атрибуты сохраняются с префиксом @. Используется Соответствие, а не Структура, потому что имена элементов могут содержать дефисы и двоеточия.

Функция УзелВЗначение(Узел)

	Результат = Новый Соответствие;
	ЕстьДочерниеЭлементы = Ложь;

	Если Узел.Атрибуты <> Неопределено Тогда
		Для Каждого Атрибут Из Узел.Атрибуты Цикл
			Результат.Вставить("@" + Атрибут.ИмяУзла, Атрибут.Значение);
		КонецЦикла;
	КонецЕсли;

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

	Если Не ЕстьДочерниеЭлементы И Результат.Количество() = 0 Тогда
		Возврат Узел.ТекстовоеСодержимое;
	ИначеЕсли Не ЕстьДочерниеЭлементы Тогда
		Результат.Вставить("#text", Узел.ТекстовоеСодержимое);
	КонецЕсли;

	Возврат Результат;

КонецФункции

// Вызов
Данные = УзелВЗначение(Документ.ДокументЭлемент);

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

Пример: выгрузка справочника в XML

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

Процедура ВыгрузитьНоменклатуру(ПутьКФайлу) Экспорт

	Запрос = Новый Запрос(
	"ВЫБРАТЬ
	|	Номенклатура.Ссылка КАК Ссылка,
	|	Номенклатура.Код КАК Код,
	|	Номенклатура.Наименование КАК Наименование,
	|	Номенклатура.Артикул КАК Артикул
	|ИЗ
	|	Справочник.Номенклатура КАК Номенклатура
	|ГДЕ
	|	НЕ Номенклатура.ПометкаУдаления
	|	И НЕ Номенклатура.ЭтоГруппа");
	Выборка = Запрос.Выполнить().Выбрать();

	Запись = Новый ЗаписьXML;
	Запись.ОткрытьФайл(ПутьКФайлу, Новый ПараметрыЗаписиXML("UTF-8", , Истина));
	Запись.ЗаписатьОбъявлениеXML();
	Запись.ЗаписатьНачалоЭлемента("products");

	Пока Выборка.Следующий() Цикл
		Запись.ЗаписатьНачалоЭлемента("product");
		Запись.ЗаписатьАтрибут("guid", XMLСтрока(Выборка.Ссылка));
		Запись.ЗаписатьАтрибут("code", СокрЛП(Выборка.Код));
		Запись.ЗаписатьНачалоЭлемента("name");
		Запись.ЗаписатьТекст(Выборка.Наименование);
		Запись.ЗаписатьКонецЭлемента();
		Запись.ЗаписатьНачалоЭлемента("sku");
		Запись.ЗаписатьТекст(Выборка.Артикул);
		Запись.ЗаписатьКонецЭлемента();
		Запись.ЗаписатьКонецЭлемента();
	КонецЦикла;

	Запись.ЗаписатьКонецЭлемента();
	Запись.Закрыть();

КонецПроцедуры

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

Обратная задача: загрузка из XML в справочник

Загрузка строится на тех же приёмах. Файл читается функцией ПрочитатьКаталог из раздела о потоковом чтении или рекурсивной функцией через DOM, а затем для каждого элемента ищется существующая запись. Если в файле есть GUID, выгруженный из 1С, ссылку можно восстановить напрямую; если GUID нет — ищите по коду или артикулу.

Для Каждого Товар Из ПрочитатьКаталог(ПутьКФайлу) Цикл
	Ссылка = Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(Товар.id));
	Объект = Ссылка.ПолучитьОбъект();
	Если Объект = Неопределено Тогда
		Объект = Справочники.Номенклатура.СоздатьЭлемент();
		Объект.УстановитьСсылкуНового(Ссылка);
	КонецЕсли;
	Объект.Наименование = Товар.name;
	Объект.Записать();
КонецЦикла;

Пример предполагает, что в атрибуте id лежит GUID; если там обычный код, конструктор УникальныйИдентификатор вызовет исключение, поэтому для внешних файлов поиск по коду через НайтиПоКоду надёжнее. Массовую загрузку выполняйте в транзакции порциями и на сервере, а ошибки отдельных элементов записывайте в журнал, чтобы один некорректный элемент не останавливал весь обмен.

«Ошибка разбора XML»: причины и решение

Сообщение «Ошибка разбора XML» означает, что текст не соответствует синтаксису XML. Ошибка разбора XML 1С обычно сопровождается номером строки и позиции — начинайте поиск с этого места. Частые причины:

  • Кодировка. В объявлении указано encoding="windows-1251", а файл фактически в UTF-8, или наоборот. Кириллица превращается в недопустимые последовательности байтов.
  • Мусор перед объявлением. Объявление <?xml ...?> должно быть самым началом документа. Пробел, перенос строки или лишний BOM, добавленный при склейке строк, ломают разбор.
  • Неэкранированные символы. Знаки & и < в тексте должны записываться как &amp; и &lt;. Это происходит, когда XML собирают конкатенацией строк, а не через ЗаписьXML.
  • Обрезанный файл. Передача прервалась, и закрывающих тегов нет.
  • Управляющие символы. Символы с кодами ниже 32 (кроме табуляции и переносов) недопустимы в XML 1.0 — их стоит удалить из текста перед записью.
  • Не XML вообще. Веб-сервис вернул HTML-страницу ошибки или JSON.

Лучшая профилактика — формировать XML только через ЗаписьXML или DOM, никогда не склеивать теги вручную: объект сам экранирует спецсимволы и записывает корректное объявление.

Типичные ошибки

  • Несбалансированные ЗаписатьНачалоЭлемента и ЗаписатьКонецЭлемента — исключение при закрытии или некорректный документ.
  • Вызов ЗаписатьАтрибут после ЗаписатьТекст или вложенного элемента — атрибуты пишутся только сразу после начала элемента.
  • Числа и даты через Строка() вместо XMLСтрока.
  • DOM для файлов в сотни мегабайт — нехватка памяти на сервере; используйте ЧтениеXML.
  • XPath без учёта пространства имён по умолчанию.
ЗадачаОбъект
Сформировать файл или строкуЗаписьXML
Прочитать большой файлЧтениеXML
Поиск узлов, изменение документаПостроительDOM, ДокументDOM, XPath
Объект 1С целикомСериализаторXDTO

Актуальность для новых версий

Объекты ЗаписьXML, ЧтениеXML, ПостроительDOM и ЗаписьDOM существуют давно и в платформе 8.3 вплоть до актуальных релизов 8.3.2x работают одинаково, так что примеры не зависят от конкретного релиза. Для больших файлов предпочтительнее потоковое чтение: DOM загружает документ в память целиком. При обмене между базами 1С с одинаковыми метаданными удобнее СериализаторXDTO, а для обменов с типовыми конфигурациями — формат EnterpriseData.

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

Чем ЧтениеXML отличается от ПостроительDOM?

ЧтениеXML читает документ последовательно, узел за узлом, и почти не расходует память. ПостроительDOM загружает весь документ в дерево, по которому можно свободно перемещаться и искать узлы через XPath, но для файлов в сотни мегабайт это затратно.

Как получить XML в строку, а не в файл?

Вызовите у ЗаписьXML метод УстановитьСтроку вместо ОткрытьФайл. После записи метод Закрыть вернёт сформированный текст.

Почему возникает «Ошибка разбора XML»?

Чаще всего из-за несоответствия кодировки в объявлении и фактической, BOM или мусора перед объявлением, неэкранированных символов & и < в тексте или обрезанного файла. Проверьте первые символы файла и его конец.

Как загрузить XML в 1С бухгалтеру без программирования?

В типовых конфигурациях для этого есть встроенные механизмы обмена и загрузки, а также универсальная обработка «Выгрузка и загрузка данных XML». Программный код нужен, когда формат файла нестандартный.

Работа с JSON в 1С: чтение, запись, даты и типичные ошибки

Интеграция и веб-сервисы

Практическое руководство по JSON в 1С: чтение строки и файла, Структура против Соответствия, запись массивов, даты, сериализация через XDTO и разбор частых ошибок.

HTTP-запросы из 1С к REST API: GET, POST и JSON

Интеграция и веб-сервисы

Готовые примеры GET и POST запросов из 1С к REST API по HTTPS: заголовки, токены, JSON, прокси, отправка файлов и универсальная функция-обёртка с логированием.

Как убрать окно авторизации при обращении к веб-сервису опубликованной базы 1С

Интеграция и веб-сервисы

При обращении к веб-сервису опубликованной базы 1С браузер каждый раз спрашивает логин и пароль. Показываем, как прописать пользователя в файле default.vrd и убрать окно авторизации.

Файл базы данных поврежден в 1С 8.3: как исправить ошибку СУБД

Базы данных и СУБД

Пошаговое восстановление файловой базы 1С при ошибке «Файл базы данных поврежден»: резервная копия, chdbfl.exe, тестирование и исправление и запасные варианты.