User:Tagtheworld/Perl

From OpenStreetMap Wiki
Jump to navigation Jump to search

hier das skript: osm_to_db.pl


vorweg: sehr interessant ist für mich auch das tool von Klaus aka user toc-rox

vgl https://forum.openstreetmap.org/viewtopic.php?id=16937


https://forum.openstreetmap.org/viewtopic.php?id=16937

der Link zur github-Ressource mit weiteren Erläuterungen: https://github.com/Klaus-Tockloth/opaquery


klaus: Im Rahmen des Projektes "Spielplätze in Münster" ist das Datenabfrage-Utility "opaQuery.pl" entstanden. Das Utility nutzt für OSM-Datenabfragen das Overpass-API unter Verwendung der Abfragesprache "Overpass-QL". Das Utility wird von der Kommandozeile aus benutzt und ist unter Linux, OS X und Windows lauffähig. Funktionsweise:

vlkcN.png

Nutzung: perl opaQuery.pl "Overpass-QL-String"

Beispiel: perl opaQuery.pl "node ['name'='Gielgen'] (50.7,7.1,50.8,7.2); out meta;"

Weitere Details zum Utility finden sich hier: http://www.easyclasspage.de/maptools/index.html

Vielleicht ist das Utility ja auch für den Einen oder Anderen von euch hilfreich.


Link zur Beschreibung des Overpass-APIs: http://wiki.openstreetmap.org/wiki/Overpass_API


unten noch mehr Perl-Zeugs: Der Autor: Da ich mich mit Perl nicht auskenne, habe ich die Bibliothek osm.pm von Garry68 benutzt. Darauf aufbauend konnte ich folgendes Perl-Script schreiben.


 
#!/usr/bin/perl 
use strict ;
use DBI;
use XML::Twig;
 
# prepare database
my $dbh=dbh(); # connect
init();
$dbh->do('USE db123');
#$dbh->do('DELETE FROM pois');
 
# sql
my $sql = 'REPLACE INTO pois VALUES (?,?,?,?,?,?)';
my $sth = $dbh->prepare($sql);
 
# set up handler
my $t = XML::Twig->new( 
  twig_handlers => { 'node' => \&node }
);
 
# parse xml
my $xml = do { local $/; <DATA> };
$t->parse($xml);
#$t->parsefile('.osm');
 
sub node {
  my ($t,$elt) = @_;
 
  my %data=(
   'id'  => $elt->att('id'),
   'lat' => $elt->att('lat'),
   'lon' => $elt->att('lon'),
   );
  for my $tag ( $elt->children() ){
    $data{$tag->att('k')} = $tag->att('v');
    #print $tag->att('k').' = '.$tag->att('v')."\n";
  }
 
  # update database
  my @f = map{ $data{$_} }('id','lat','lon','name','amenity','operator');
  if ($f[3] ne '' && $f[4] ne '' && $f[5] ne ''){
    print "-- INSERT --\n".
    (join "\n",@f).
    "\n\n";
    $sth->execute(@f);
  }
}
 
 
sub init {
  $dbh-> do('CREATE DATABASE IF NOT EXISTS db123 
             DEFAULT CHARACTER SET latin1 
             COLLATE latin1_german2_ci');
  $dbh->do('USE db123');
  $dbh->do('CREATE TABLE IF NOT EXISTS pois (
           id       BIGINT(20) UNSIGNED NOT NULL,
           lat      FLOAT(10,7) NOT NULL,
           lon      FLOAT(10,7) NOT NULL,
           name     VARCHAR(255) COLLATE utf8_bin NOT NULL,
           amenity  VARCHAR(255) COLLATE utf8_bin NOT NULL,
           operator VARCHAR(255) COLLATE utf8_bin NOT NULL,
           PRIMARY KEY  (id)
          ) ENGINE=MyISAM DEFAULT 
            CHARSET=utf8 
            COLLATE=utf8_bin');
}
 
sub dbh {
  my $dsn = "DBI:mysql:database=;host=localhost";
  my $dbh = DBI->connect($dsn, 'user', 'pwd',
            {RaiseError => 1, PrintError => 1}) 
            or die (Error connecting " $DBI::errstr");
}


ferner noch das skript create_db.pl



  #!/usr/bin/perl -w
 
  use strict ;
  use OSM::osm ;
 
  my $file ;
  my $nodeUser ;
  my @nodeTags ;
  my $nodeTags ;
  my $ref1 ;
  my $line ;
  my $tag;
  my $nodeName;
 
  my $id ="1" ;
  my $lat ;
  my $lon ;
  my $name ;
  my $amenity ;
  my $operator ;
  my $vending;  
 
 
$file = "pois.osm" ; open(AUSGABE, ">mysql.txt");
$file = "pois.osm" ;
 
 
  openOsmFile ($file) ;
  open(AUSGABE, ">c:/osm/planet/mysql.txt");
  ($id, $lon, $lat, $nodeUser, $ref1) = getNode2 () ;
 
  while ($id != -1 ) {
      $name ="" ;
      $amenity ="" ;
      $operator ="" ;
      $vending ="" ;
 
      @nodeTags = @$ref1;
      foreach my $tag    (@nodeTags) {
          if ($tag->[0] eq "name") { $name = scalar ($tag->[1] )};
          if ($tag->[0] eq "amenity") { $amenity = scalar ($tag->[1] )};
          if ($tag->[0] eq "operator") { $operator = scalar ($tag->[1] )};
          if ($tag->[0] eq "vending") { $vending = scalar ($tag->[1] )}
          }            
      if     ($name ne "" | $amenity ne "" | $operator ne"" | $vending ne"")
          {print AUSGABE "$id^$lat^$lon^$name^$amenity^$operator^$vending\n";}
      ($id, $lon, $lat, $nodeUser, $ref1) = getNode2 () ;
 
  }
  close(AUSGABE);
  closeOsmFile () ;


In PHP koennte das so etwa ausshen



$xmlstr = <<<XML
<data>
<node id="2064639440" lat="49.4873181" lon="8.4710548">
    <tag k="amenity" v="restaurant"/>
    <tag k="cuisine" v="turkish"/>
    <tag k="email" v="info@lynso.de"/>
    <tag k="name" v="Kilim  - Café und Bar Restaurant"/>
    <tag k="opening_hours" v="Su-Th 17:00-1:00; Fr, Sa 17:00-3:00"/>
    <tag k="operator" v="Cengiz Kaya"/>
    <tag k="phone" v="06 21 - 43 755 371"/>
    <tag k="website" v="http://www.kilim-mannheim.de/"/>
  </node>
  <node id="2126473801" lat="49.4851170" lon="8.4756295">
    <tag k="amenity" v="restaurant"/>
    <tag k="cuisine" v="italian"/>
    <tag k="email" v="mannheim1@vapiano.de"/>
    <tag k="fax" v="+49 621 1259 779"/>
    <tag k="name" v="Vapiano"/>
    <tag k="opening_hours" v="Su-Th 10:00-24:00; Fr-Sa 10:00-01:00"/>
    <tag k="operator" v="Vapiano"/>
    <tag k="phone" v="+49 621 1259 777"/>
    <tag k="website" v="http://www.vapiano.de/newsroom/?store=29"/>
    <tag k="wheelchair" v="yes"/>
  </node>
  <node id="667927886" lat="49.4909673" lon="8.4764904">
    <tag k="addr:city" v="Mannheim"/>
    <tag k="addr:country" v="DE"/>
    <tag k="addr:housenumber" v="5"/>
    <tag k="addr:postcode" v="68161"/>
    <tag k="addr:street" v="Collinistraße"/>
    <tag k="amenity" v="restaurant"/>
    <tag k="name" v="Churrascaria Brasil Tropical"/>
    <tag k="phone" v="+496211225596"/>
    <tag k="wheelchair" v="limited"/>
  </node>
  <node id="689928440" lat="49.4798794" lon="8.4853418">
    <tag k="amenity" v="restaurant"/>
    <tag k="cuisine" v="greek"/>
    <tag k="email" v="epirus70@hotmail.de"/>
    <tag k="fax" v="0621/4407 762"/>
    <tag k="name" v="Epirus"/>
    <tag k="opening_hours" v="Mo-Sa 12:00-15:00,18:00-24:00"/>
    <tag k="phone" v="0621/4407 761"/>
    <tag k="smoking" v="separated"/>
    <tag k="website" v="http://epirus-ma.blogspot.com/"/>
    <tag k="wheelchair" v="no"/>
  </node>
  <node id="689928445" lat="49.4799409" lon="8.4851357">
    <tag k="amenity" v="restaurant"/>
    <tag k="cuisine" v="italian"/>
    <tag k="email" v="gianlucascurti@ristorante-augusta.de"/>
    <tag k="name" v="Ristorante Augusta"/>
    <tag k="opening_hours" v="Mo-Fr 12:00-14:00,18:00-23:00;Su 12:00-14:00,18:00-23:00"/>
    <tag k="phone" v="0621 449872"/>
    <tag k="website" v="ristorante-augusta.com/"/>
    <tag k="wheelchair" v="no"/>
  </node>
</data>
 
XML;
 
$fields = array('id','lat','lon','name','amenity','operator','vending');
$xml = simplexml_load_string($xmlstr);
 
$dbdata = array();
foreach ($xml->node AS $node) {
    $nodedata = array_fill_keys($fields,'');
    $nodedata['id']  = $node['id'];
    $nodedata['lat'] = isset($node['lat']) ? $node['lat'] : 0;
    $nodedata['lon'] = isset($node['lon']) ? $node['lon'] : 0;
    foreach ($node->tag AS $tag) {
        $k = (string)$tag['k'];
        $v = (string)$tag['v'];
        IF (isset($nodedata[$k])) {
            $nodedata[$k] = $v;
        }
    }
    $dbdata[] = vsprintf("(%d, %10.7f, %10.7f, '%s', '%s', '%s', '%s')", $nodedata);
}
 
$fieldlist = JOIN(',', $fields);
$sql = "REPLACE INTO pois ($fieldlist) VALUES\n" . JOIN(",\n", $dbdata);
 
echo "<pre>$sql</pre>";
$db->query($sql);

Apropos Robustheit: hier noch etwas zum DB-Anschluss u. den Feldern anstatt das hardcoded zu machen - wie hier:


$fields = array('id','lat','lon','name','amenity','operator','vending');

hiermit koennte man jeee zusätzliche Spalte der pois-Tabelle hinzufügen.

$sql = "SHOW COLUMNS FROM pois";
$fields = array();
$res = $db->query($sql);
while ($row = $res->fetch_row()) {
    $fields[] = $row[0];
}