Анализ данных OSM для получения узлов с дочерним узлом

Я загружаю данные Open Street Map для небольшого региона, я хочу отфильтровать данные, чтобы получить узлы со специальной категорией.

Вот пример данных OSM

<node id="505126369" lat="31.2933856" lon="34.2687443" user="JumpStart International" uid="125156" visible="true" version="1" changeset="2568758" timestamp="2009-09-22T13:05:10Z"/> <node id="505126372" lat="31.2682934" lon="34.2745680" user="JumpStart International" uid="125156" visible="true" version="1" changeset="2568758" timestamp="2009-09-22T13:05:10Z"/> <node id="505126375" lat="31.2953082" lon="34.3471630" user="JumpStart International" uid="125156" visible="true" version="1" changeset="2568758" timestamp="2009-09-22T13:05:10Z"/> <node id="505126378" lat="31.2807872" lon="34.2757999" user="JumpStart International" uid="125156" visible="true" version="1" changeset="2568758" timestamp="2009-09-22T13:05:11Z"> <tag k="amenity" v="school"/> <tag k="name" v="Al Aqqad Basic &amp; Secondary Female School"/> <tag k="name:ar" v="مدرسة العقاد الأساسية والثانوية للبنات"/> </node> 

Я хочу, чтобы все данные об этих школах, больницах.

Если бы кто-нибудь сделал синтаксический анализ XML с PHP или Java, я бы очень хотел поделиться им со мной и всеми интересами.

Редактировать Вот простой старт, который у меня есть

 $dataFile = base_url() . 'media/files/osmdata/map_3.xml'; //echo ($dataFile); $xml = simplexml_load_file($dataFile); // $countTotal = count($xml->node); // echo 'here'.$countTotal; foreach ($xml as $key => $val) { var_dump($val); // can't manage things overs here } 

Ниже приведен небольшой пример API OSM Overpass с PHP SimpleXML, который я скомпилировал, потому что у нас его нет здесь для PHP, и мне нравится OSM, поэтому давайте покажем некоторые полезные примеры.

В первой части показано, как вы можете запросить конечную точку Overpass со стандартным PHP. Эта часть вам не нужна, поскольку вы уже сохранили данные на своем жестком диске:

 <?php /** * OSM Overpass API with PHP SimpleXML / XPath * * PHP Version: 5.4 - Can be back-ported to 5.3 by using 5.3 Array-Syntax (not PHP 5.4's square brackets) */ // // 1.) Query an OSM Overpass API Endpoint // $query = 'node ["amenity"~".*"] (38.415938460513274,16.06338500976562,39.52205163048525,17.51220703125); out;'; $context = stream_context_create(['http' => [ 'method' => 'POST', 'header' => ['Content-Type: application/x-www-form-urlencoded'], 'content' => 'data=' . urlencode($query), ]]); # please do not stress this service, this example is for demonstration purposes only. $endpoint = 'http://overpass-api.de/api/interpreter'; libxml_set_streams_context($context); $start = microtime(true); $result = simplexml_load_file($endpoint); printf("Query returned %2\$d node(s) and took %1\$.5f seconds.\n\n", microtime(true) - $start, count($result->node)); 

Для вас вторая часть интереснее. Это запрос данных XML, которые у вас уже есть. Это проще всего сделать с помощью xpath, используемая библиотека PHP XML основана на libxml, который поддерживает XPath 1.0, который очень хорошо охватывает различные запросы.

В следующем примере перечислены все школы и попытки получить их имена. Я еще не занимался переводами, потому что у моих образцовых данных их нет, но вы также можете искать все имена, включая переводы, и просто предпочитаете конкретный):

 // // 2.) Work with the XML Result // # get all school nodes with xpath $xpath = '//node[tag[@k = "amenity" and @v = "school"]]'; $schools = $result->xpath($xpath); printf("%d School(s) found:\n", count($schools)); foreach ($schools as $index => $school) { # Get the name of the school (if any), again with xpath list($name) = $school->xpath('tag[@k = "name"]/@v') + ['(unnamed)']; printf("#%02d: ID:%' -10s [%s,%s] %s\n", $index, $school['id'], $school['lat'], $school['lon'], $name); } 

Ключевым моментом здесь является запрос xpath. Используются два, первый – узлы с определенными тегами. Я думаю, что это самое интересное для вас:

 //node[tag[@k = "amenity" and @v = "school"]] 

В этой строке говорится: «Дайте мне все элементы узла , у которых есть элемент тега, внутри которого есть значение атрибута k « amenity » и значение атрибута v « школа » . Это условие, которое вы должны отфильтровывать те узлы , которые помечены с помощью школы amenity.

Далее xpath используется снова, теперь относительно этих школьных узлов, чтобы увидеть, есть ли имя, и если это необходимо для его получения:

 tag[@k = "name"]/@v' 

В этой строке указано: Относительно текущего узла дайте мне атрибут v из элемента тега, который в качестве значения атрибута k «name» . Как вы можете видеть, некоторые части снова похожи на строку раньше. Я думаю, вы можете принять их в соответствии с вашими потребностями.

Поскольку не все школьные узлы имеют имя, для целей отображения предоставляется строка по умолчанию, добавляя ее в массив результатов (затем пустой):

 list($name) = $school->xpath('tag[@k = "name"]/@v') + ['(unnamed)']; ^^^^^^^^^^^^^^^ Provide Default Value 

Итак, вот мои результаты для этого примера кода:

 Query returned 907 node(s) and took 1.10735 seconds. 10 School(s) found: #00: ID:332534486 [39.5017565,16.2721899] Scuola Primaria #01: ID:1428094278 [39.3320912,16.1862820] (unnamed) #02: ID:1822746784 [38.9075566,16.5776597] (unnamed) #03: ID:1822755951 [38.9120272,16.5713431] (unnamed) #04: ID:1903859699 [38.6830409,16.5522243] Liceo Scientifico Statale A. Guarasci #05: ID:2002566438 [39.1347698,16.0736924] (unnamed) #06: ID:2056891127 [39.4106679,16.8254844] (unnamed) #07: ID:2056892999 [39.4124687,16.8286119] (unnamed) #08: ID:2272010226 [39.4481717,16.2894353] SCUOLA DELL'INFANZIA SAN FRANCESCO #09: ID:2272017152 [39.4502366,16.2807664] SCUOLA MEDIA 

Надеюсь, это уже полезно, дайте мне знать, если у вас появятся дополнительные разъяснения.


(by rbwilkinson ): Так вы можете добавить дополнительные параметры для поиска других значений. в следующем примере найдены другие свойства в пределах одного километра:

 $query = 'node ["addr:postcode"~"RM12"] (51.5557914,0.2118915,51.5673083,0.2369398); node (around:1000) ["amenity"~"fast_food"]; out;'; $context = stream_context_create(['http' => [ 'method' => 'POST', 'header' => ['Content-Type: application/x-www-form-urlencoded'], 'content' => 'data=' . urlencode($query), ]]); $endpoint = 'http://overpass-api.de/api/interpreter'; libxml_set_streams_context($context); $result = simplexml_load_file($endpoint); printf("Query returned %2\$d node(s) and took %1\$.5f seconds.\n\n", microtime(true) - $start, count($result->node)); }