Почему аварийно закрывается 1С 7.7 при вызове v7plus ТекущийЭлементВВидеОбъекта и как правильно читать XML?

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

При интеграции и обмене данными в среде 1С:Предприятие 7.7 разработчики часто сталкиваются с критической ошибкой: в процессе чтения структуры XML с помощью внешней компоненты v7plus.dll на строке вызова ТекущийЭлементВВидеОбъекта() программа мгновенно зависает и аварийно завершает работу без вывода информативных сообщений об ошибке. Разберем по шагам причины такого поведения платформы и рассмотрим надежные альтернативные способы обработки XML-документов.

Выясним причину: почему падает v7plus.dll

Проанализируем механизм работы компоненты v7plus.dll (объект AddIn.XMLParser). Данная библиотека представляет собой COM-обертку над системным парсером Microsoft XML Parser. Сбои происходят по следующим основным причинам:

  1. Нарушение работы со связанными библиотеками MSXML: устаревшие версии компоненты обращаются к библиотекам msxml3.dll или msxml4.dll. Если регистрация этих COM-серверов в операционной системе повреждена либо возник конфликт версий, попытка инициализации COM-объекта узла вызывает исключение нарушения прав доступа к памяти (Access Violation), приводящее к краху процесса 1cv7.exe или 1cv7s.exe.
  2. Переполнение буфера при больших объемах узлов: метод ТекущийЭлементВВидеОбъекта() пытается полностью построить в памяти DOM-дерево со всеми вложенными тегами и атрибутами. При наличии длинных строк без переносов, сложных структур пространств имен (Namespaces) или большого объема данных внутренний буфер парсера переполняется.
  3. Позиционирование курсора чтения: если считыватель спозиционирован не на валидном открывающем узле XML-элемента, функция не может выполнить корректное преобразование. Конструкция Попытка ... Исключение в 1С 7.7 не способна перехватить критические сбои неуправляемого C++ кода внешней компоненты.

Способ 1. Использование потокового чтения без преобразования в DOM-объект

Если необходимо продолжать использовать v7plus.dll, откажемся от метода ТекущийЭлементВВидеОбъекта() в пользу последовательного обхода дерева документа. Рассмотрим, как это сделать безопаснее:

  1. Выполняем навигацию по элементам методами Спуститься(), Следующий() и Подняться().
  2. Считываем значения узлов непосредственно через свойства СвойстваТекущегоУзла.Значение и СвойстваТекущегоУзла.Имя, не создавая промежуточный COM-объект узла.
  3. Если требуется получить XML-фрагмент целиком в виде текста, используем вызов ТекущийЭлементВВидеСтроки() с последующим разбором строковыми функциями платформы.
  4. Проверяем версию библиотеки: в каталоге базы и каталоге платформы BIN должен использоваться файл v7plus.dll версии не ниже 7.70.0.11.

Способ 2. Чтение документа через MSXML2.DOMDocument (Рекомендуемый подход)

Наиболее стабильным и производительным решением в 1С 7.7 является прямой отказ от v7plus.dll при разборе XML в пользу системного COM-объекта MSXML2.DOMDocument. Посмотрим на алгоритм универсальной инициализации объекта и разбора XML-файла со сложной структурой и пространствами имен.

Разберем функцию безопасной инициализации парсера с перебором доступных в системе версий:


Функция глСоздатьDOMDocument() Экспорт 
    DOMDocument = 0;
    Попытка 
        DOMDocument = СоздатьОбъект("Msxml2.DOMDocument.6.0");
    Исключение 
        DOMDocument = 0;
        Попытка 
            DOMDocument = СоздатьОбъект("Msxml2.DOMDocument.4.0"); 
        Исключение 
            DOMDocument = 0;            
            Попытка 
                DOMDocument = СоздатьОбъект("Msxml2.DOMDocument");
            Исключение 
                Сообщить("В системе не установлена ни одна из библиотек XML от Microsoft!", "!"); 
                Возврат 0;
            КонецПопытки;            
        КонецПопытки;        
    КонецПопытки;
    
    DOMDocument.async = 0;
    DOMDocument.validateOnParse = -1;
    DOMDocument.resolveExternals = -1;
    Возврат DOMDocument;
КонецФункции

Теперь рассмотрим практический пример загрузки файла, проверки на ошибки парсинга и обхода коллекции вложенных узлов с извлечением значений реквизитов:


DOMDocument = глСоздатьDOMDocument();
Если DOMDocument = 0 Тогда
    Возврат;
КонецЕсли;

DOMDocument.load(ТекФайл);

Если DOMDocument.parseError.errorCode <> 0 Тогда
    Сообщить("Ошибка проверки файла " + ТекФайл + "! Код ошибки: " + DOMDocument.parseError.errorCode, "!");
    Возврат;
КонецЕсли;              

Узел1 = DOMDocument.getElementsByTagName("ns:Documents").Item(0);
Узел2 = Узел1.getElementsByTagName("ns:Document").Item(0);
Узел3 = Узел2.getElementsByTagName("ns:ReplyAP").Item(0);
Выборка = Узел3.getElementsByTagName("rap:Products").Item(0);

Для а = 0 По Выборка.childNodes.length - 1 Цикл
    Состояние("Обработано " + (а + 1) + " строк");
    ТекУзел = Выборка.childNodes(а);
    
    Объем = 0;
    Если ТекУзел.getElementsByTagName("pref:Capacity").length > 0 Тогда
        Объем = СокрЛП(ТекУзел.getElementsByTagName("pref:Capacity").Item(0).Text);
        Объем = СтрЗаменить(Объем, ",", ".");
        Объем = Число(Объем);
    КонецЕсли;
    
    ПолнНаименование = СокрЛП(ТекУзел.getElementsByTagName("pref:FullName").Item(0).Text);
    Если ТекУзел.getElementsByTagName("pref:ShortName").length > 0 Тогда
        Наименование = ТекУзел.getElementsByTagName("pref:ShortName").Item(0).Text;
    Иначе
        Наименование = ПолнНаименование;
    КонецЕсли;
    
    КодЕГАИС = СокрЛП(ТекУзел.getElementsByTagName("pref:AlcCode").Item(0).Text);
    КодВидаАП = СокрЛП(ТекУзел.getElementsByTagName("pref:ProductVCode").Item(0).Text);
    
    хмл_Производитель = ТекУзел.getElementsByTagName("pref:Producer").Item(0);
    ИННПроизводитель = "";
    Если хмл_Производитель.getElementsByTagName("oref:INN").length > 0 Тогда
        ИННПроизводитель = СокрЛП(хмл_Производитель.getElementsByTagName("oref:INN").Item(0).Text);
    КонецЕсли;
    
    ИД_Производитель = СокрЛП(хмл_Производитель.getElementsByTagName("oref:ClientRegId").Item(0).Text);
    НаимПроизводитель = СокрЛП(хмл_Производитель.getElementsByTagName("oref:ShortName").Item(0).Text);
    
    // Запись данных в справочник
    Если Спр.НайтиПоКоду(КодЕГАИС, 0) = 0 Тогда
        Спр.Новый();
    КонецЕсли;
    
    Спр.Код = КодЕГАИС;
    Спр.Наименование = Наименование;
    Спр.ПолнНаименование = ПолнНаименование;
    Спр.Объем = Объем;
    Спр.Производитель = ИД_Производитель;
    Спр.ПроизводительНаим = НаимПроизводитель;
    Спр.ПроизводительИНН = ИННПроизводитель;
    Спр.Записать();
КонецЦикла;

Рассмотренный подход через MSXML2.DOMDocument гарантирует стабильную работу конфигурации без аварийных завершений, корректно обрабатывает специфические префиксы узлов и исключает зависимость от проблемных версий v7plus.dll.

← На главную