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

Публикация № 610725

Программирование - Практика программирования

XPath пространства имен РазыменовательПространствИменDOM ВычислитьВыражениеXPath xml Яндекс геокодирование разбор парсинг

34
Есть некоторые нюансы разбора с помощью 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 работать не будет.

34

См. также

Специальные предложения

Комментарии
Избранное Подписка Сортировка: Древо
1. NiNAH 18 19.04.17 14:02 Сейчас в теме
//*[local-name()="found"]
А такое выражение XPath разве не работает?
2. shmellevich 121 19.04.17 23:08 Сейчас в теме
(1) это сработает если там один "found", а если будет несколько и еще в разных ветках, как тогда будет результат?
в примере описано точность попадания в нужный узел и получение нужного "found" ))
3. ifal 285 20.04.17 07:08 Сейчас в теме
Вот тут хорошо написано про пространство имен http://infostart.ru/public/280340/, но у вас пример наглядный.
4. brr 179 20.04.17 10:15 Сейчас в теме
(3) При изучении вопроса я читал этот пост. Именно для наглядности добавил свой.
frkbvfnjh; +1 Ответить
6. frkbvfnjh 513 13.05.19 14:22 Сейчас в теме
(4) Согласен, что в Вашей статье написано гораздо понятнее, нагляднее и более кратко
5. brr 179 20.04.17 10:17 Сейчас в теме
Оставьте свое сообщение