При обработке XML-файлов с помощью COM-объекта MSXML2.DOMDocument часто возникает ситуация, когда методы selectNodes или selectSingleNode возвращают пустой результат. Причина заключается в наличии пространства имен по умолчанию (атрибут xmlns="http://hl7.org/fhir") в корневом узле документа.
Согласно спецификации XPath 1.0, если имя тега в запросе указывается без префикса (например, //MedicationPrescription), поиск выполняется только среди элементов без пространства имен. Если у документа задан дефолтный xmlns, все его дочерние узлы наследуют это пространство имен, и обычный XPath-запрос перестает их находить.
Рассмотрим несколько способов решения этой задачи при разработке на 1С.
Для корректной работы XPath-запросов в MSXML2.DOMDocument необходимо зарегистрировать псевдоним (префикс) пространства имен с помощью метода setProperty. Заданный префикс (например, ns) затем используется во всех XPath-выражениях.
Разберем по шагам реализацию этого метода:
MSXML2.DOMDocument.6.0 и загружаем XML-файл.SelectionNamespaces, связывая нужный URI с префиксом.Посмотрим на пример кода:
XML = CreateObject("MSXML2.DOMDocument.6.0");
XML.Load("d:\файл.xml");
// Регистрируем пространство имен и задаем префикс ns
XML.setProperty("SelectionNamespaces", "xmlns:ns=""http://hl7.org/fhir""");
// Выполняем выборку узлов с использованием зарегистрированного префикса
all = XML.selectNodes("//ns:MedicationPrescription");
length = all.length;
Для i = 0 по length - 1 Цикл
Узел = all.item(i);
// Для обращения к дочерним элементам также обязательно указываем префикс
УзелId = Узел.selectSingleNode("ns:id");
Если ПустоеЗначение(УзелId) = 0 Тогда
Значение = УзелId.getAttribute("value");
Сообщить("Значение ID: " + Значение);
КонецЕсли;
КонецЦикла;
Если для работы с документом не требуются сложные XPath-выражения, можно применить стандартный метод getElementsByTagName. Данный метод ищет узлы по их локальному имени, игнорируя пространства имен.
Проанализируем пример использования:
XML = CreateObject("MSXML2.DOMDocument.6.0");
XML.Load("d:\файл.xml");
// Получаем коллекцию элементов по имени тега без учета пространства имен
all = XML.getElementsByTagName("MedicationPrescription");
length = all.length;
Для i = 0 по length - 1 Цикл
Узел = all.item(i);
СписокId = Узел.getElementsByTagName("id");
Если СписокId.length > 0 Тогда
Значение = СписокId.item(0).getAttribute("value");
Сообщить("Значение ID: " + Значение);
КонецЕсли;
КонецЦикла;
Ещё один вариант — обращение к локальному имени элемента с помощью XPath-функции local-name(). Важно учитывать, что при выборе дочерних элементов их также нужно запрашивать через local-name(), иначе выборка вернет пустое значение.
Рассмотрим пример кода:
XML = CreateObject("MSXML2.DOMDocument.6.0");
XML.Load("d:\файл.xml");
// Ищем теги по их локальному имени
all = XML.selectNodes("//*[local-name()='MedicationPrescription']");
length = all.length;
Для i = 0 по length - 1 Цикл
Узел = all.item(i);
// Дочерний узел выбираем аналогично по local-name()
УзелId = Узел.selectSingleNode("*[local-name()='id']");
Если ПустоеЗначение(УзелId) = 0 Тогда
Значение = УзелId.getAttribute("value");
Сообщить("Значение ID: " + Значение);
КонецЕсли;
КонецЦикла;
Для повышения точности поиска можно дополнить условие проверкой пространства имен через функцию namespace-uri():
all = XML.selectNodes("//*[local-name()='MedicationPrescription' and namespace-uri()='http://hl7.org/fhir']");
Наиболее стандартизированным решением при работе с DOM в 1С является регистрация пространства имен через setProperty("SelectionNamespaces", ...). В более простых сценариях разбора структуры XML подходят методы getElementsByTagName или использование local-name() в XPath-запросах.