XPath и пространства имен на примере разбора файла ответа сервиса геокодирования Яндекс

Есть некоторые нюансы разбора с помощью Xpath xml-файла, в котором используются несколько пространств имен. Приведен разбор такого файла на примере файла ответа сервиса геокодирования Яндекс.

Файл ответа сервиса геокодирования Яндекса имеет следующую структуру:

<?xml version="1.0" encoding="utf-8"?>
<ymaps xmlns="http://maps.yandex.ru/ymaps/1.x" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="     http://maps.yandex.ru/business/1.x http://maps.yandex.ru/schemas/business/1.x/business.xsd     http://maps.yandex.ru/geocoder/1.x http://maps.yandex.ru/schemas/geocoder/1.x/geocoder.xsd     http://maps.yandex.ru/psearch/1.x http://maps.yandex.ru/schemas/psearch/1.x/psearch.xsd     http://maps.yandex.ru/search/1.x http://maps.yandex.ru/schemas/search/1.x/search.xsd     http://maps.yandex.ru/web/1.x http://maps.yandex.ru/schemas/web/1.x/web.xsd     http://maps.yandex.ru/search/internal/1.x http://maps.yandex.ru/schemas/search/internal/1.x/internal.xsd">
<GeoObjectCollection>
<metaDataProperty xmlns="http://www.opengis.net/gml">
<GeocoderResponseMetaData xmlns="http://maps.yandex.ru/geocoder/1.x">
<request>РЯЗАНСКАЯ ОБЛАСТЬ, РЯЗАНЬ Г, ПЕРВОМАЙСКИЙ ПР-КТ, ДОМ № 62, КОРПУС 1</request>
<found>1</found>
<results>1</results>
</GeocoderResponseMetaData>
</metaDataProperty>
<featureMember xmlns="http://www.opengis.net/gml">
<GeoObject xmlns="http://maps.yandex.ru/ymaps/1.x" xmlns:gml="http://www.opengis.net/gml" gml:id="1">
<metaDataProperty xmlns="http://www.opengis.net/gml">
<GeocoderMetaData xmlns="http://maps.yandex.ru/geocoder/1.x">
<kind>house</kind>
<text>Россия, Рязань, Первомайский проспект, 62к1</text>
<precision>exact</precision>
<Address xmlns="http://maps.yandex.ru/address/1.x">
<country_code>RU</country_code>
<formatted>Рязань, Первомайский проспект, 62к1</formatted>
<Component>
<kind>country</kind>
<name>Россия</name>
</Component>
<Component>
<kind>province</kind>
<name>Центральный федеральный округ</name>
</Component>
<Component>
<kind>province</kind>
<name>Рязанская область</name>
</Component>
<Component>
<kind>area</kind>
<name>городской округ Рязань</name>
</Component>
<Component>
<kind>locality</kind>
<name>Рязань</name>
</Component>
<Component>
<kind>street</kind>
<name>Первомайский проспект</name>
</Component>
<Component>
<kind>house</kind>
<name>62к1</name>
</Component>
</Address>
<AddressDetails xmlns="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0">
<Country>
<AddressLine>Рязань, Первомайский проспект, 62к1</AddressLine>
<CountryNameCode>RU</CountryNameCode>
<CountryName>Россия</CountryName>
<AdministrativeArea>
<AdministrativeAreaName>Рязанская область</AdministrativeAreaName>
<SubAdministrativeArea>
<SubAdministrativeAreaName>городской округ Рязань</SubAdministrativeAreaName>
<Locality>
<LocalityName>Рязань</LocalityName>
<Thoroughfare>
<ThoroughfareName>Первомайский проспект</ThoroughfareName>
<Premise>
<PremiseNumber>62к1</PremiseNumber>
</Premise>
</Thoroughfare>
</Locality>
</SubAdministrativeArea>
</AdministrativeArea>
</Country>
</AddressDetails>
</GeocoderMetaData>
</metaDataProperty>
<description xmlns="http://www.opengis.net/gml">Рязань, Россия</description>
<name xmlns="http://www.opengis.net/gml">Первомайский проспект, 62к1</name>
<boundedBy xmlns="http://www.opengis.net/gml">
<Envelope>
<lowerCorner>39.711716 54.627376</lowerCorner>
<upperCorner>39.719927 54.632139</upperCorner>
</Envelope>
</boundedBy>
<Point xmlns="http://www.opengis.net/gml">
<pos>39.715821 54.629758</pos>
</Point>
</GeoObject>
</featureMember>
</GeoObjectCollection>
</ymaps>

Получим из него информацию о том, что информация об адресе  была найдена сервисом. Для этого воспользуемся методом ВычислитьВыражениеXPath объекта ДокументDOM:

ЧтениеХМЛ = Новый ЧтениеXML;
ЧтениеХМЛ.ОткрытьФайл(ИмяФайла);

ПостроительДом = Новый ПостроительDOM;
ДокументДом = ПостроительДом.Прочитать(ЧтениеХМЛ);

СоответствиеПространств = Новый Соответствие;
СоответствиеПространств.Вставить("y","http://maps.yandex.ru/ymaps/1.x");
СоответствиеПространств.Вставить("o","http://www.opengis.net/gml");
СоответствиеПространств.Вставить("g","http://maps.yandex.ru/geocoder/1.x");
СоответствиеПространств.Вставить("a","http://maps.yandex.ru/address/1.x");

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

РезультатПоиска = ДокументДом.ВычислитьВыражениеXPath("/y:ymaps/y:GeoObjectCollection/o:metaDataProperty/g:GeocoderResponseMetaData/g:found",ДокументДом.ЭлементДокумента,Разыменователь);

Если РезультатПоиска <> Неопределено Тогда
Найдено = РезультатПоиска.ПолучитьСледующий();
Сообщить("Результат поиска данных геокодирования "+Найдено.ТекстовоеСодержимое);
КонецЕсли;

Фрагмент кода, устанавливающий соответствие пространств имен, далее ПИ, префиксам:

СоответствиеПространств = Новый Соответствие;
СоответствиеПространств.Вставить("y","http://maps.yandex.ru/ymaps/1.x");
СоответствиеПространств.Вставить("o","http://www.opengis.net/gml");
СоответствиеПространств.Вставить("g","http://maps.yandex.ru/geocoder/1.x");
СоответствиеПространств.Вставить("a","http://maps.yandex.ru/address/1.x");

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

Префиксы нужны для того, чтобы XPath понимала, какой узел к какому ПИ относится. Узлы ymaps и GeoObjectCollection относятся к ПИ «http://maps.yandex.ru/ymaps/1.x», для которого установлен префикс y, поэтому в строке запроса мы указываем «/y:ymaps/y:GeoObjectCollection». Обращаю внимание на особенность указания ПИ узлов, если ПИ указан у узла, то его дочерние узлы, по умолчанию, имеют тот же ПИ, и явно его указывать у них не надо. Узел metaDataProperty принадлежит к ПИ «http://www.opengis.net/gml», а узлы GeocoderResponseMetaData и found к ПИ «http://maps.yandex.ru/geocoder/1.x», причем узел found принадлежит неявно. Узлы, принадлежащие ПИ «http://maps.yandex.ru/address/1.x», не используются в примере, поэтому соответствие префикса этому ПИ можно удалить.

Ничего сложного в описанном нет, но в явном виде информации на Инфостарте я не нашел, а если указанные нюансы не учитывать, XPath работать не будет.

6 Comments

  1. NiNAH

    //*[local-name()=»found»]

    А такое выражение XPath разве не работает?

    Reply
  2. shmellevich

    (1) это сработает если там один «found», а если будет несколько и еще в разных ветках, как тогда будет результат?

    в примере описано точность попадания в нужный узел и получение нужного «found» ))

    Reply
  3. ifal

    Вот тут хорошо написано про пространство имен http://infostart.ru/public/280340/, но у вас пример наглядный.

    Reply
  4. brr

    (3) При изучении вопроса я читал этот пост. Именно для наглядности добавил свой.

    Reply
  5. brr

    Вот что у яндекса есть по этому вопросу https://tech.yandex.ru/maps/doc/geocoder/desc/reference/geocoder_namespaces-docpage/

    Reply
  6. frkbvfnjh

    (4) Согласен, что в Вашей статье написано гораздо понятнее, нагляднее и более кратко

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *