Как вычислить выражение XPath в XML с разными пространствами имён в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При обработке XML-документов в 1С (например, файлов графических схем или данных интеграции) часто возникает ситуация, когда разные теги документа находятся в разных пространствах имён (xmlns). Если родительский элемент относится к одному URI, а вложенный переопределяет пространство имён, стандартный выбор узлов через XPath может возвращать пустой результат.

Разберем, почему так происходит, и проанализируем основные способы решения этой задачи в платформе 1С.

Причина проблемы при работе с XPath и DOM

В стандарте XPath 1.0 элементы, находящиеся в пространстве имён по умолчанию (объявленные через xmlns="..."), требуют явного указания префикса. Если автоматический РазыменовательПИ создан для узла с пространством имён схемы (например, http://v8.1c.ru/8.2/data/graphscheme), он не сможет автоматически сопоставить вложенные узлы <item>, принадлежащие другому пространству имён (например, http://v8.1c.ru/8.1/data/core).

Способ 1. Последовательный поиск с динамической сменой разыменователя

Рассмотрим вариант, когда выполнение поиска разбивается на два последовательных шага. Сначала мы находим контейнер в основном пространстве имён схемы, а затем создаем новый разыменователь для вложенного пространства имён и ищем требуемые элементы.

Посмотрим на пример реализации:


// 1. Поиск элемента с основным пространством имён
РазыменовательЭталон = ДокументDOMЭталон.СоздатьРазыменовательПИ();
Результат = ДокументDOMЭталон.ВычислитьВыражениеXPath(
    "./xmlns:description", 
    ЭлементDOMВариант, 
    РазыменовательЭталон, 
    ТипРезультатаDOMXPath.НеупорядоченныйИтераторУзлов
);
ЭлементDOMНаименованиеВарианта = Результат.ПолучитьСледующий();

// 2. Создание разыменователя для v8 core и выборка вложенных тегов
Если ЭлементDOMНаименованиеВарианта <> Неопределено Тогда
    Разыменовательv8core = ДокументDOMЭталон.СоздатьРазыменовательПИ("xmlns", "http://v8.1c.ru/8.1/data/core");
    Результат = ДокументDOMЭталон.ВычислитьВыражениеXPath(
        "./xmlns:item/xmlns:content", 
        ЭлементDOMНаименованиеВарианта, 
        Разыменовательv8core, 
        ТипРезультатаDOMXPath.НеупорядоченныйИтераторУзлов
    );
    
    СвойствоЭлементаDOM = Результат.ПолучитьСледующий();
    Пока СвойствоЭлементаDOM <> Неопределено Цикл
        // Обработка найденных узлов
        СвойствоЭлементаDOM = Результат.ПолучитьСледующий();
    КонецЦикла;
КонецЕсли;

Способ 2. Использование функций local-name() в одном XPath-выражении

Чтобы найти узлы за один подход без пересоздания разыменователей, можно обращаться к тегам через функцию XPath local-name(). Это позволяет искать узлы по их имени независимо от того, какое пространство имён или префикс им назначены.

Проанализируем пример единого запроса:


ВыражениеXPath = "./*[local-name()='description']/*[local-name()='item']/*[local-name()='content']";

Результат = ДокументDOMЭталон.ВычислитьВыражениеXPath(
    ВыражениеXPath, 
    ЭлементDOMВариант, 
    Неопределено, 
    ТипРезультатаDOMXPath.НеупорядоченныйИтераторУзлов
);

НайденныйУзел = Результат.ПолучитьСледующий();
Пока НайденныйУзел <> Неопределено Цикл
    // Обработка текста или атрибутов узла
    НайденныйУзел = Результат.ПолучитьСледующий();
КонецЦикла;

Если требуется строго ограничить поиск конкретным пространством имён для отдельного тега, выражение можно усложнить с помощью проверки namespace-uri():


ВыражениеXPath = "./*[local-name()='description']/*[local-name()='item' and namespace-uri()='http://v8.1c.ru/8.1/data/core']/*[local-name()='content']";

Способ 3. Регистрация нескольких пространств имён через Соответствие

Ещё один вариант решения в 1С — сопоставить каждое используемое пространство имён собственному префиксу. Для этого передадим объект Соответствие в конструктор РазыменовательПространствИменDOM.

Разберем по шагам создание такого разыменователя:

  1. Создаем объект Соответствие и заполняем пары "Префикс" — "URI пространства имён".
  2. Инициализируем РазыменовательПространствИменDOM с переданным соответствием.
  3. Используем заданные префиксы прямо в XPath-запросе.

СоответствиеПИ = Новый Соответствие;
СоответствиеПИ.Вставить("gs", "http://v8.1c.ru/8.2/data/graphscheme");
СоответствиеПИ.Вставить("core", "http://v8.1c.ru/8.1/data/core");

Разыменователь = Новый РазыменовательПространствИменDOM(СоответствиеПИ);

ВыражениеXPath = "./gs:description/core:item/core:content";

Результат = ДокументDOMЭталон.ВычислитьВыражениеXPath(
    ВыражениеXPath, 
    ЭлементDOMВариант, 
    Разыменователь, 
    ТипРезультатаDOMXPath.НеупорядоченныйИтераторУзлов
);

Вывод: Если структура XML содержит динамические или сложные пространства имён, удобнее всего использовать функцию local-name(). Если же пространства имён строго определены стандартом обмена, наиболее чистым решением будет явное задание префиксов через Соответствие и РазыменовательПространствИменDOM.

← На главную