При интеграции и обмене данными в среде 1С:Предприятие 7.7 разработчики часто сталкиваются с критической ошибкой: в процессе чтения структуры XML с помощью внешней компоненты v7plus.dll на строке вызова ТекущийЭлементВВидеОбъекта() программа мгновенно зависает и аварийно завершает работу без вывода информативных сообщений об ошибке. Разберем по шагам причины такого поведения платформы и рассмотрим надежные альтернативные способы обработки XML-документов.
Проанализируем механизм работы компоненты v7plus.dll (объект AddIn.XMLParser). Данная библиотека представляет собой COM-обертку над системным парсером Microsoft XML Parser. Сбои происходят по следующим основным причинам:
msxml3.dll или msxml4.dll. Если регистрация этих COM-серверов в операционной системе повреждена либо возник конфликт версий, попытка инициализации COM-объекта узла вызывает исключение нарушения прав доступа к памяти (Access Violation), приводящее к краху процесса 1cv7.exe или 1cv7s.exe.ТекущийЭлементВВидеОбъекта() пытается полностью построить в памяти DOM-дерево со всеми вложенными тегами и атрибутами. При наличии длинных строк без переносов, сложных структур пространств имен (Namespaces) или большого объема данных внутренний буфер парсера переполняется.Попытка ... Исключение в 1С 7.7 не способна перехватить критические сбои неуправляемого C++ кода внешней компоненты.Если необходимо продолжать использовать v7plus.dll, откажемся от метода ТекущийЭлементВВидеОбъекта() в пользу последовательного обхода дерева документа. Рассмотрим, как это сделать безопаснее:
Спуститься(), Следующий() и Подняться().СвойстваТекущегоУзла.Значение и СвойстваТекущегоУзла.Имя, не создавая промежуточный COM-объект узла.ТекущийЭлементВВидеСтроки() с последующим разбором строковыми функциями платформы.BIN должен использоваться файл v7plus.dll версии не ниже 7.70.0.11.Наиболее стабильным и производительным решением в 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.