2013-04-21 191 views
1

我为一个小区域下载了打开的街道地图数据,我想过滤数据以获取具有特殊类别的节点。OSM数据解析以获取带有子节点的节点

这里是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> 

我想整个学校的样品,在数据的医院。

如果有人用PHP或Java进行XML解析,我将非常感谢与我和所有兴趣分享它。

编辑 下面是一个简单的开始我刚才

$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 

    } 
+0

你坚持在看什么部分的过程中,有什么不为你工作?当Google搜寻'php parse osm'(当然,'php parse xml')时,我会看到一些有趣的链接。为什么不先查看那些? – 2013-04-21 08:12:17

+0

我开始制作我自己的XML解析器,但我对XML不太熟悉。我坚持循环遍历节点,只得到父节点。 – palAlaa 2013-04-21 08:16:07

+1

@palAlaa:请问您如何使用PHP来显示问题。然后我们可以给你一些提示和/或给你一个答案。否则你的描述有点宽泛,我会猜测你遇到困难以及如何解决问题。 – hakre 2013-04-21 08:43:17

回答

4

以下是用PHP的SimpleXML一点OSM立交桥API的例子,我已经编译,因为我们没有在这里为PHP和我爱OSM,让我们来展示一些有用的例子。

第一部分显示了如何使用标准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"]] 

此行说:给我说有一个标签元素的所有节点元素中它具有ķ属性值“舒适”v属性值“学校”。这是你必须过滤那些标记为设施学校的节点的条件。

而且XPath的再次使用,现在相对于那些学校的节点,看看是否有一个名字,如果是把它牵回家:

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

此行说:相对于当前节点,给我v属性来自标签元素作为k属性值“名称”。正如你所看到的,一些零件再次与之前的生产线类似。我认为你们都可以采纳他们来满足你的需求。

因为不是所有的学校节点有一个名字,默认的字符串是通过将其添加到(当时空的)结果阵列提供用于显示目的:

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 

我希望这已经有用了,如果您有更多的澄清问题,请告诉我。


(由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)); 
} 
+0

这是非常棒的答案,这正是我需要的。感谢名单上百万:) – palAlaa 2013-04-23 07:13:53

+0

aweseome - 我的方式喜欢这个很好的例子 – zero 2014-06-12 12:29:23

+1

- 如果你要收集所有学校 ,想提取立交桥-API学校:注意一些学校包括作为节点,而另一些地区(多边形或多面体)或两者。你需要跟踪 节点,方式和关系 - 所有类型的对象 CF http://wiki.openstreetmap.org/wiki/Overpass_API/Language_Guide#All_kind_of_objects让所有的 – zero 2014-06-13 15:21:48