Как и чем заменить AddIn.XMLParser от v7plus.dll при работе с XML в 1С 7.7?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

Рассмотрим частую задачу, с которой сталкиваются программисты при поддержке старых баз на платформе 1С 7.7 — замену устаревшей внешней компоненты v7plus.dll на более современные и стабильные инструменты для работы с XML-документами.

Разберем основные причины, по которым отказ от v7plus.dll является правильным шагом:

  1. Проблемы с 64-битными ОС: Компонента жестко привязана к старым версиям системного парсера (MSXML 3.0) и часто вызывает проблемы с регистрацией на современных версиях Windows Server.
  2. Ограничения по памяти: При работе с большими файлами компонента может приводить к аварийному завершению работы 1С (падению).
  3. Устаревший подход: В современных операционных системах уже встроены мощные COM-объекты, которые справляются с задачей быстрее и стабильнее.

Использование встроенного парсера MSXML2.DOMDocument

Посмотрим на классический способ загрузки и обхода XML-документа с помощью библиотеки Microsoft XML (MSXML). Прямым аналогом загрузки документа является объект MSXML2.DOMDocument.6.0.

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


Процедура ОбработатьУзел(Узел, Уровень=0)
    Состояние(Уровень);
    
    КолвоУзлов = Узел.childNodes.length;
    Для СчУзлов = 0 По КолвоУзлов-1 Цикл
        
        ТекУзел = Узел.childNodes.item(СчУзлов);
        Если ТекУзел.nodeType <> 1 Тогда // пропускаем текстовые узлы
            Продолжить;
        КонецЕсли;
        
        Стр = Формат("","С"+Уровень*8);
        СтрАтрибуты = "";
        
        Для счАтрибутов = 0 По ТекУзел.attributes.length-1 Цикл
            Атрибут = ТекУзел.attributes.item(счАтрибутов);
            СтрАтрибуты = СтрАтрибуты + ?(СтрАтрибуты="","",";") + Атрибут.nodename+"="+Атрибут.value;
        КонецЦикла;
        
        ТекстУзла = "";
        Если ТекУзел.childNodes.length = 1 Тогда
            Если ТекУзел.childNodes.item(0).nodetype = 3 Тогда
                ТекстУзла = ТекУзел.childNodes.item(0).text;
            КонецЕсли;
        КонецЕсли;
        
        Стр = Стр + ТекУзел.tagName + ?(СтрАтрибуты="","","("+СтрАтрибуты+")" ) + ": " + ТекстУзла;
        Сообщить(Стр);
        
        // Рекурсивный вызов для дочерних узлов
        ОбработатьУзел(ТекУзел, Уровень+1);
    КонецЦикла;
    
    Состояние("");
КонецПроцедуры

Вызовем эту процедуру, передав ей корневой элемент загруженного документа:


Иксемель = СоздатьОбъект("Microsoft.XMLDOM"); // или MSXML2.DOMDocument.6.0
Иксемель.Load(ФайлДанных);
Корень = Иксемель.DocumentElement;
ОбработатьУзел(Корень, 0);
Иксемель = "";

Решение проблемы с кодировкой (UTF-8)

Платформа 1С 7.7 работает в кодировке Windows-1251. Если мы читаем XML-файл в кодировке UTF-8 стандартными методами, мы можем получить "кракозябры". Разберем, как решить эту проблему с помощью объекта ADODB.Stream.

Рассмотрим фрагмент кода, где мы получаем ответ по HTTP (или читаем из файла), а затем декодируем его в нужную кодировку перед загрузкой в парсер:


Стрим = СоздатьОбъект("ADODB.Stream"); 
Стрим.Mode = 3;
Стрим.Type = 1;
Стрим.Open(); 
// ... здесь мы пишем данные в поток (например, WinHttp.responseBody) ...
Стрим.Position = 0;
Стрим.Type = 2; // Текстовые данные
Стрим.Charset = "utf-8";
Ответ = Стрим.ReadText();
Стрим.Close();

XML_DOM = CreateObject("MSXML2.DOMDocument.6.0");
XML_DOM.LoadXML(Ответ); // Загружаем корректно раскодированный текст

Универсальная обертка для плавного перехода

Если вы не хотите сильно менять существующий код, проанализируем подход с написанием универсальных функций. Они будут проверять, доступна ли компонента v7plus.dll, и если нет (или если нужно форсировать использование MSXML), будут использовать методы DOMDocument.

Посмотрим на пример такой универсальной функции получения дочернего узла:


Функция ВыбратьУзел(РодительскийЭлемент, ИмяЭлементаДляПоиска, ПропускатьОшибки = 0) Экспорт
    Если ПустоеЗначение(РодительскийЭлемент) = 1 Тогда
        Возврат ПолучитьПустоеЗначение();
    ИначеЕсли (ИспользоватьV7plus = 0) ИЛИ (КомпонентаV7plusЗагружена = 2) Тогда
        // Используем методы MSXML
        ИмяЭлементаДляПоиска = Сред(ИмяЭлементаДляПоиска, Найти(ИмяЭлементаДляПоиска,":")+1);
        Для й = 0 По РодительскийЭлемент.ChildNodes.length-1 Цикл
            Узел = РодительскийЭлемент.ChildNodes.item(й);
            Если Узел.baseName = ИмяЭлементаДляПоиска Тогда
                Возврат Узел; 
            КонецЕсли;
        КонецЦикла; 
    Иначе
        // Используем методы v7plus
        Узел = РодительскийЭлемент.ВыбратьУзел(ИмяЭлементаДляПоиска);
        Если ПустоеЗначение(Узел)=0 Тогда
            Возврат Узел;
        КонецЕсли;
    КонецЕсли;
    
    Если ПропускатьОшибки = 0 Тогда 
        Сообщить("В файле XML не удалось найти элемент: " + ИмяЭлементаДляПоиска, "!");
    КонецЕсли;
    Возврат ПолучитьПустоеЗначение();
КонецФункции

Альтернативные варианты обработки огромных файлов

Если вам нужно обрабатывать файлы обмена гигантских размеров (сотни мегабайт), обычный DOM-парсер (и MSXML, и v7plus) может не справиться, так как полностью загружает файл в оперативную память. Выясним, какие существуют альтернативы:

  1. Использование SAX-парсера: Создайте объект MSXML2.SAXXMLReader. В отличие от DOM, он не загружает весь документ в память, а читает его последовательно, как поток (stream), вызывая события при нахождении каждого нового тега. Это полный аналог метода СоздатьПоследовательноСчитываемыйДокумент().
  2. Внешние компоненты: Обратите внимание на компоненты 1cpp.dll (1С++) или OpenXML от Romix. Они содержат оптимизированные методы работы с XML и текстом.
  3. Прямое чтение текста: Для простых по структуре, но объемных файлов можно использовать объект Scripting.FileSystemObject или штатный класс 1С Текст. Читая файл построчно, можно искать нужные значения через строковые функции Найти() и Сред(). Этот метод требует больше ручного кода, но работает невероятно быстро и потребляет минимум оперативной памяти.
← На главную