User:Tagtheworld/PHP und Overpass

From OpenStreetMap Wiki
Jump to: navigation, search



weitere Themen auf Unterseiten
Sprachen und Techniken
PHP und Overpass



osm - overpass-api and PHPSimpleXML


new to the work with PHPSimpleXML


I want to filter the data to get the nodes with special category. Here is sample of the OSM data I want to get the whole schools within an area. The first script runs well - but now i want to refine the search and add more tags. Finally i want to store all into the MySQL-db

This example is taken from http://stackoverflow.com/questions/16129184/osm-data-parsing-to-get-the-nodes-with-child and is discussed furthermore here: http://stackoverflow.com/questions/24191370/osm-overpass-api-with-php-simplexml-xpath-refining-a-search credits go out to Hakr


So we need to make some XML parsing with PHP:

The following is a little OSM Overpass API example with PHP SimpleXML I've compiled it because I love OSM, so let's show some useful examples. The first part shows how we can query an Overpass Endpoint with standard PHP. we do not need that part if we have already saved the data on the harddisk


    <?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));
    
    //
    // 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);
    }
    
    ?>


For you the second part is more interesting. That is querying the XML data you have already. This is most easily done with xpath, the used PHP XML library is based on libxml which supports XPath 1.0 which covers the various querying needs very well. The following example lists all schools and tries to obtain their names as well. I have not covered translations yet because my sample data didn't have those, but you can also look for all kind of names including translations and just prefer a specific one):


The key point here are the xpath queries. Two are used, the first one to get the nodes that have certain tags. I think this is the most interesting one for you:

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


This line says: Give me all node elements that have a tag element inside which has the k attribute value "amenity" and the v attribute value "school". This is the condition you have to filter out those nodes that are tagged with amenity school. Further on xpath is used again, now relative to those school nodes to see if there is a name and if so to fetch it:

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


This line says: Relative to the current node, give me the v attribute from a tag element that as the k attribute value "name". As you can see, some parts are again similar to the line before. I think you can both adopt them to your needs. Because not all school nodes have a name, a default string is provided for display purposes by adding it to the (then empty) result array:

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


so far so good: **note**. i need to have the adress-data, of the school with

cf [url=http://wiki.openstreetmap.org/wiki/Key:addr]Key:addr - OpenStreetMap Wiki[/url]

and even more important

cf [url=http://wiki.openstreetmap.org/wiki/Key:contact]Key:contact - OpenStreetMap Wiki[/url]

contact:phone contact:fax contact:website contact:email

btw. here my results for that code-example:


    martin@linux-70ce:~/php> 
    martin@linux-70ce:~/php> php osm1.php
    Query returned 1691 node(s) and took 3.34569 seconds.
    
    23 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.1349460,16.0736446]  (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
    #10: ID:2358307794  [39.5015031,16.3905965]  I.I.S.S. Liceo Statale V. Iulia
    #11: ID:2358307796  [39.4926280,16.3853662]  Liceo Classico
    #12: ID:2358307797  [39.4973761,16.3858275]  Scuola Media
    #13: ID:2358307800  [39.5015527,16.3941156]  I.T.C. e per Geometri
    #14: ID:2358307801  [39.4983862,16.3807796]  Istituto Professionale
    #15: ID:2358344885  [39.4854617,16.3832419]  Istituto Tecnico Statale Commerciale G. Falcone
    #16: ID:2448031004  [38.6438417,16.3873106]  (unnamed)
    #17: ID:2458139204  [39.0803263,17.1291649]  Sacro Cuore
    #18: ID:2552412313  [39.0765212,17.1224610]  (unnamed)
    #19: ID:2582443083  [39.0815417,17.1178983]  Liceo Socio Biologico Gravina
    #20: ID:2585754364  [38.8878393,16.4076323]  Scuola Elementare
    #21: ID:2585754366  [38.8877600,16.4076216]  Scuola Media
    #22: ID:2755576944  [39.3641541,17.1310900]  (unnamed)
    martin@linux-70ce:~/php>
   note. i need to have the adress-data, of the shool with 
 

and even more important [url=http://wiki.openstreetmap.org/wiki/Key:contact]Key:contact - OpenStreetMap Wiki[/url]

   contact:phone 
   contact:fax 	
   contact:website 
   contact:email

questionː How to add this .. into the query ?


Answerː if we change the bounding box entry


  $query = 'node
      ["amenity"~".*"]
      (38.415938460513274,16.06338500976562,39.52205163048525,17.51220703125);
    out;';


....into that following ...ː


$query = 'node
  ["addr:postcode"~"RM12"]
  (51.5557914,0.2118915,51.5673083,0.2369398);
  node
  (around:100000)
  ["amenity"~"school"];
           out;';

$context = stream_context_create(['http' => [
    'method'  => 'POST',
    'header' => ['Content-Type: application/x-www-form-urlencoded'],
    'content' => 'data=' . urlencode($query),
]]);

we get more than 2170 results:


,,, ,,, note more than 2000 records,,,,

#2171: ID:2837001831  [51.1783749,-0.7970866]  More House School
#2172: ID:2865091022  [50.9090614,-0.5565425]  Dorset House School
#2173: ID:2882477853  [51.6261198,-0.7349665]  Bowerdean Primary School
#2174: ID:2901434856  [51.6542477,-0.3098923]  The Haberdashers' Aske's Girls School
#2175: ID:2901434857  [51.6565707,-0.3129822]  The Haberdashers' Aske's Boys School


questionsː̠


can i do some rework of the area-data like so:

    [place] => SimpleXMLElement Object
            (
                [@attributes] => Array
                    (
                        [place_id] => 331526
                        [osm_type] => node
                        [osm_id] => 96209423
                        [place_rank] => 15
                        [boundingbox] => 44.4361381530762,44.4361419677734,26.1027431488037,26.1027450561523
                        [lat] => 44.436139
                        [lon] => 26.1027436
                        [display_name] => București, Sector 2, Bucuresti, România, European Union
                        [class] => place
                        [type] => city
                        [importance] => 0.73231672860554
                        [icon] => http://nominatim.openstreetmap.org/images/mapicons/poi_place_city.p.20.png
                    )
     
            )

found that hereː Parse XML response with SimpleXML http://www.codeproject.com/Questions/607176/ParseplusXMLplusresponsepluswithplusSimpleXML Questionː is this doable!`?



...and how to finally store all into the MySQL-db ?




weitere Themen auf Unterseiten
Sprachen und Techniken
PHP und Overpass
OpenLayers Datenbankanbindung