При работе с XML-файлами в 1С, особенно в рамках механизмов обмена данными, часто возникает задача предварительного анализа данных. Например, нам нужно прочитать дату документа из файла обмена, сравнить её с датой запрета загрузки и, если проверка не пройдена, пропустить объект. Однако стандартный объект 1С ЧтениеXML работает по принципу однопроходного потокового сканера (модель StAX). Это означает, что как только мы вызвали метод Прочитать() и дошли до нужного узла, вернуться назад штатными средствами самого объекта невозможно.
Разберем подробно, как обойти это ограничение, какие есть способы «сброса» выборки и как правильно организовать фильтрацию данных в «Конвертации данных 2.1».
Проанализируем ситуацию: объект ЧтениеXML спроектирован для максимально быстрой обработки файлов любого объема с минимальным потреблением оперативной памяти. Он не загружает весь документ в память (в отличие от DOM), а «бежит» по нему вперед. У него отсутствуют методы типа ПерейтиВНачало() или возможность клонирования текущего состояния. Если вы прочитали файл до конца или до середины, указатель зафиксирован в текущей позиции.
Самый простой и надежный способ «сбросить» выборку — это закрыть текущее чтение и открыть его заново. Это инициализирует указатель на начало файла. Рассмотрим, как это выглядит в коде:
// Предположим, у нас есть объект ЧтениеФайла, который уже открыт
ПутьКФайлу = ЧтениеФайла.ИмяФайла; // Сохраняем путь
ЧтениеФайла.Закрыть();
// Открываем заново, чтобы начать чтение с нуля
ЧтениеФайла.ОткрытьФайл(ПутьКФайлу);
В контексте «Конвертации данных 2.1» этот метод может быть опасен, так как объект ЧтениеXML (часто передаваемый как ФайлОбмена) управляется самим ядром обработки обмена. Его закрытие вручную может привести к ошибкам в основном цикле загрузки.
Чтобы не сбивать позицию основного объекта ЧтениеXML, который используется системой для загрузки, мы можем создать временный вспомогательный объект. Проанализируем этот алгоритм: мы открываем тот же самый файл вторым объектом, быстро находим нужные данные, закрываем его, а основной объект продолжает работу с того места, где он находился.
Рассмотрим пример реализации в обработчике "Перед загрузкой" (ПКО):
// Создаем новый независимый экземпляр для анализа
ВспомогательноеЧтение = Новый ЧтениеXML;
ВспомогательноеЧтение.ОткрытьФайл(ИмяФайлаОбмена);
// Быстро прокручиваем до нужного нам узла или значения
Пока ВспомогательноеЧтение.Прочитать() Цикл
Если ВспомогательноеЧтение.ТипУзла = ТипУзлаXML.НачалоЭлемента
И ВспомогательноеЧтение.Имя = "Дата" Тогда
ВспомогательноеЧтение.Прочитать(); // Читаем текстовое содержимое узла
ЗначениеДаты = ВспомогательноеЧтение.Значение;
// Выполняем проверку
Если Дата(ЗначениеДаты) < ДатаЗапрета Тогда
Отказ = Истина;
КонецЕсли;
Прервать; // Мы нашли что искали, выходим из цикла
КонецЕсли;
КонецЦикла;
ВспомогательноеЧтение.Закрыть();
Важный момент: если вы используете КД 2.1, убедитесь, что параметр ИмяФайлаОбмена доступен в вашем обработчике. Это позволит вам «заглянуть» в файл, не нарушая работу основного парсера.
Выясним причину, почему иногда Отказ = Истина не срабатывает так, как ожидает разработчик. В «Конвертации данных» существует иерархия обработчиков. Если вы хотите, чтобы объект вообще не создавался и не записывался, проверку нужно делать в событии «Перед загрузкой» самого ПКО.
Если же вы пытаетесь отменить загрузку в событии «После загрузки», то объект к этому моменту уже может быть физически создан в памяти 1С. Чтобы гарантированно отменить запись, используйте связку параметров:
// В обработчике "После загрузки"
Если Не НужнаЗагрузкаОбъекта Тогда
Отказ = Истина;
ОбъектМодифицирован = Ложь; // Указываем системе, что объект не менялся
КонецЕсли;
Однако стоит помнить, что в 1С:Предприятие 8 параметр ОбъектМодифицирован по умолчанию часто стоит в Истина, если выполнялся код обработчика. Явное присвоение Ложь помогает избежать лишних попыток записи платформой.
Если нам нужно проанализировать структуру текущего объекта целиком, не переоткрывая файл, мы можем воспользоваться объектом ПостроительDOM. Метод Прочитать() у построителя может принимать объект ЧтениеXML.
Посмотрим на пример:
// Мы стоим в начале узла объекта
Построитель = Новый ПостроительDOM;
ДокументDOM = Построитель.Прочитать(ЧтениеXML); // Читает текущий узел со всеми вложенными элементами
// Теперь у нас есть дерево DOM только для этого объекта
// Мы можем обращаться к свойствам через XPath или обход коллекции
УзлыСвойств = ДокументDOM.ПолучитьЭлементыПоИмени("Свойство");
// ... логика анализа ...
Внимание: после выполнения Построитель.Прочитать(ЧтениеXML), основной курсор ЧтениеXML переместится в самый конец прочитанного узла. Если после анализа вы решите, что объект нужно загружать, стандартный механизм КД его уже не увидит, так как позиция чтения «проскочила» данные. Этот метод идеален только для принятия решения о пропуске данных.
Объект. Метод ЧтениеXML.ПолучитьАтрибут() позволяет прочитать значение, не сдвигая курсор чтения.ФабрикаXDTO.ПрочитатьXML() для всего файла обмена, если он весит более нескольких десятков мегабайт. Это приведет к значительному потреблению оперативной памяти и может вызвать аварийное завершение работы сеанса.Таким образом, хотя прямого метода «сброса» в ЧтениеXML не существует, использование вспомогательного объекта чтения или правильная расстановка фильтров в событиях КД позволяют эффективно решать задачи предварительного анализа данных.