Как найти подчиненные узлы в XML в 1С 7.7: от v7plus к MSXML DOMDocument

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

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

Причины ошибок при использовании v7plus и XMLParser

Рассмотрим стандартный пример, с которым столкнулся автор темы. В XML-файле присутствует корневой элемент Rasshifrovka, содержащий подчиненные блоки ApplicationArea и DataArea. При попытке найти узел прямо из объекта документа вызовами Документ.ВыбратьУзел("ApplicationArea") или Документ.ВыбратьУзлы("ApplicationArea") система возвращает ошибку:

«Значение не представляет агрегатный объект (Наименование)»

Выясним причину такого поведения XMLParser из библиотеки v7plus:

  1. Метод ВыбратьУзел() без указания относительного или абсолютного пути ищет узел непосредственно на текущем уровне обращения. Если поиск выполняется от самого объекта Документ, метод ожидает, что ApplicationArea является корневым тегом. Поскольку корнем является Rasshifrovka, метод возвращает пустое значение (Неопределено или пустой объект). При попытке обратиться к свойству .Наименование у пустого результата возникает ошибка.
  2. Для правильной адресации через v7plus необходимо явно задавать полные пути XPath:

    Код правильного обращения через полный путь:

    
    // Выборка с указанием полного пути
    ApplicationArea = Документ.ВыбратьУзел("Rasshifrovka/ApplicationArea");
    
    // Выборка с рекурсивным поиском по всему дереву
    ApplicationArea = Документ.ВыбратьУзел("//ApplicationArea");
    

Однако штатная компонента v7plus имеет существенные ограничения по поддержке стандартов XML и зависима от версии библиотеки MSXML, установленной в операционной системе. Для полноценной и стабильной работы рекомендуем переходить на прямую работу с системным COM-объектом MSXML2.DOMDocument.

Переход на MSXML2.DOMDocument

Использование COM-объекта MSXML2.DOMDocument предоставляет полный спектр возможностей стандартов DOM и XPath. Рассмотрим основные шаги по инициализации и загрузке документа в 1С 7.7.

Для предотвращения ошибок и зависаний при загрузке файлов важно задать правильные параметры объекта:


// Создаем объект MSXML2.DOMDocument
dom = СоздатьОбъект("MSXML2.DOMDocument.6.0");

// Отключаем асинхронную загрузку, чтобы код ждал полного открытия файла
dom.async = 0;

// Отключаем загрузку внешних DTD-схем и проверку валидности для ускорения
dom.resolveExternals = 0;
dom.validateOnParse = 0;

// Задаем язык запросов XPath для корректной работы selectSingleNode и selectNodes
dom.setProperty("SelectionLanguage", "XPath");

// Загружаем XML-файл
Если dom.load(ПолноеИмяФайла) = 0 Тогда
    Предупреждение("Ошибка чтения XML файла!");
КонецЕсли;

Способ 1. Использование методов selectSingleNode и selectNodes (XPath)

Рассмотрим, как выполнять выборку данных с помощью языковых конструкций XPath. Метод selectSingleNode возвращает первое совпадение, а selectNodes — коллекцию найденных элементов.

Посмотрим на практический пример обхода табличной части (блока roster) и считывания шапки документа:


Функция ДанныеАтрибута(Узел, ИмяУзла)
    Попытка
        Возврат СокрЛП(Узел.selectSingleNode(ИмяУзла).text);
    Исключение
        Возврат "";
    КонецФункции
КонецФункции

Процедура РазобратьXML()
    // Чтение элемента из шапки по относительному пути
    ОписаниеДоставки = ДанныеАтрибута(dom.documentElement, "deliveryCondition/contract/number");
    Сообщить("Номер договора: " + ОписаниеДоставки);

    // Получаем список всех строк товаров в документе
    СтрокиТоваров = dom.documentElement.selectSingleNode("roster");
    Если ПустоеЗначение(СтрокиТоваров) = 0 Тогда
        КоличествоСтрок = СтрокиТоваров.childNodes.length;
        Для Сч = 0 По КоличествоСтрок - 1 Цикл
            ТекУзел = СтрокиТоваров.childNodes.item(Сч);
            
            // Получаем значение подчиненного тега <number>
            НомерПозиции = ДанныеАтрибута(ТекУзел, "number");
            Сообщить("Позиция №: " + НомерПозиции);
        КонецЦикла;
    КонецЕсли;
КонецПроцедуры

Способ 2. Безопасный поиск через getElementsByTagName

В реальных условиях файлы от контрагентов могут не содержать отдельных необязательных тегов. Если применить selectSingleNode к несуществующему тегу и сразу обратиться к свойству .text, возникнет ошибка выполнения. Разберем универсальные вспомогательные функции для безопасного извлечения значений и узлов с помощью метода getElementsByTagName.


// Функция для безопасного получения значения тега по имени
Функция ПолучитьЗначениеУзлаПоИмени(Узел, Имя)
    Результат = "";
    Если ПустоеЗначение(Узел) = 1 Тогда
        Возврат Результат;
    КонецЕсли;
    
    // Ищем все входящие элементы с указанным именем
    Коллекция = Узел.getElementsByTagName(Имя);
    Если Коллекция.length > 0 Тогда
        Результат = Коллекция.Item(0).Text;
    КонецЕсли;
    
    Возврат Результат;
КонецФункции

// Функция для безопасного получения самого узла
Функция ПолучитьУзелПоИмени(Узел, Имя)
    Результат = "";
    Если ПустоеЗначение(Узел) = 1 Тогда
        Возврат Результат;
    КонецЕсли;
    
    Коллекция = Узел.getElementsByTagName(Имя);
    Если Коллекция.length > 0 Тогда
        Результат = Коллекция.Item(0);
    КонецЕсли;
    
    Возврат Результат;
КонецФункции

Метод getElementsByTagName ищет теги с указанным именем на любой глубине вложенности относительно переданного узла, что позволяет легко находить глубоко расположенные элементы без построения полной цепочки родительских тегов.

Особенность работы с пространством имен (xmlns)

Если обрабатываемый XML-файл содержит пространствo имен (например, <Rasshifrovka xmlns="http://site.com/schema">), стандартные методы поиска по имени тега могут вернуть пустой результат. Чтобы решить эту проблему в MSXML, необходимо зарегистрировать псевдоним пространства имен перед поиском:


// Регистрация префикса пространства имен
dom.setProperty("SelectionNamespaces", "xmlns:ns='http://site.com/schema'");

// Поиск узла с использованием заданного префикса ns
Узел = dom.selectSingleNode("//ns:ApplicationArea");
Если ПустоеЗначение(Узел) = 0 Тогда
    Сообщить(Узел.text);
КонецЕсли;

Обработка XML-файлов большого объема (SAX)

Модель DOM загружает весь документ в оперативную память. Если размер XML-файла превышает 50–100 МБ, это может вызвать переполнение памяти в 1С 7.7. В таких ситуациях рекомендуется использовать последовательный SAX-парсер (MSXML2.SAXXMLReader.6.0), который считывает документ «на лету» событие за событием без загрузки всего дерева в память.

Итоги

  1. Для корректного поиска элементов через штатный v7plus используйте рекурсивный синтаксис //ИмяТега или укажите полный путь от корня.
  2. Наиболее надежным решением в 1С 7.7 является использование COM-объекта MSXML2.DOMDocument.6.0.
  3. Для безопасного извлечения значений из XML используйте проверку длины коллекции через getElementsByTagName() или обрабатывайте исключения при обращении к selectSingleNode().text.
← На главную