User:GranD/API Perl example

From OpenStreetMap Wiki
Jump to: navigation, search
#!/usr/bin/perl
use strict;

binmode(STDIN, ':utf8');
binmode(STDERR, ':utf8');

use LWP::UserAgent;
use HTTP::Request;
use XML::Parser;
use utf8;
use POSIX qw/strftime/;

my $cs_create_url = "http://api.openstreetmap.org/api/0.6/changeset/create";
sub cs_upload_url {
	my $id = shift;
	return "http://api.openstreetmap.org/api/0.6/changeset/$id/upload";
}
sub cs_close_url {
	my $id = shift;
	return "http://api.openstreetmap.org/api/0.6/changeset/$id/close";
}
sub el_get_url {
	my $type = shift;
	my $id = shift;
	return "http://api.openstreetmap.org/api/0.6/$type/$id";
}

my $login = "login";
my $passwd = "password";

my $ua = LWP::UserAgent->new;
$ua->credentials ('api.openstreetmap.org:80', 'Web Password', $login => $passwd);
my ($req, $res, $changeset_id);
my %node, my %tags, my @nd;

$req = HTTP::Request->new(PUT=>$cs_create_url);
$req->content_type('text/xml');
$req->content("<osm><changeset><tag k='comment' v='some comment here'/></changeset></osm>");
print STDERR "Opening changeset...";
$res = $ua->request($req) || die("Cannot open changeset, test your connection");
$changeset_id = $res->content;
print STDERR " succesful, id=$changeset_id\n";

#creating XML Parser
my $parser = new XML::Parser(ProtocolEncoding => 'UTF-8', Handlers => {Start => \&xml_start});

#parsing input data
my $timestamp = strftime ("%Y-%m-%dT%H:%M:%S.0+04:00", gmtime);
my $text = "<osmChange version=\"0.3\" generator=\"Perl\">\n    <modify>\n";
while(<>) {
	chomp;
    next if /^\s*#/; #ignore comments
    @nd = ();
	if (/(node|way)\t(\d+)\t(.+)/) {
		my ($ctype, $cid, $cname) = ($1, $2, $3);
		print STDERR "Requesting data for $ctype $cid...\n";
		$req = HTTP::Request->new(GET=>el_get_url($ctype, $cid));
		$res = $ua->request($req);
		my $xml = $res->content;
        #print STDERR $xml."\n";
		%node = %tags = ();
		$parser->parse($xml);
		$tags{'name:ru'} = $cname;
		$node{'timestamp'} = $timestamp;
        if ($ctype eq 'node') {
            $text .= "        <node id=\"$node{id}\" timestamp=\"$node{timestamp}\" lat=\"$node{lat}\" lon=\"$node{lon}\" changeset=\"$changeset_id\" version=\"$node{version}\">\n";
        } elsif ($ctype eq 'way') {
            $text .= "        <way id=\"$node{id}\" timestamp=\"$node{timestamp}\" changeset=\"$changeset_id\" version=\"$node{version}\">\n";
        }
		for my $k(sort keys %tags) {
			$text .= "            <tag k=\"$k\" v=\"$tags{$k}\"/>\n";
		}
        for my $r(@nd) {
            $text .= "            <nd ref=\"$r\"/>\n";
        }
		$text .= "        </$ctype>\n";
	} else {
		print STDERR "String <$_> is not valid\n";
	}
}
$text .= "    </modify>\n</osmChange>";
if (utf8::is_utf8($text)) {
	utf8::encode($text); #important!
}

$req = HTTP::Request->new(POST=>cs_upload_url($changeset_id));
$req->content_type('text/xml');
$req->content($text);
print STDERR "Uploading...\n";
$res = $ua->request($req);
print STDERR $res->content;

$req = HTTP::Request->new(PUT=>cs_close_url($changeset_id));
print STDERR "Closing changeset... ";
$res = $ua->request($req);
print STDERR $res->content."\n";

#subs

sub xml_start {
	my ($elem, $tag, %attr) = @_;
	if ($tag eq 'node' || $tag eq 'way') {
		for my $k (keys %attr) {
			$node{$k} = $attr{$k};
		}
	} elsif ($tag eq 'tag') {
		$tags{$attr{'k'}} = xml_escape($attr{'v'});
	} elsif ($tag eq 'nd') {
        push @nd, $attr{'ref'};
    }
}

sub xml_escape {
    my $s = shift;
    $s =~ s/"/&quot;/g;
    $s =~ s/'/&apos;/g;
    $s =~ s/</&lt;/g;
    $s =~ s/>/&gt;/g;
    return $s;
}