Ich hätte da ein superhochaufwendiges™ Skript:
#!/usr/bin/perl
#-------------------------------------------------------------------------------
# $Id: osmmerge.pl,v 1.7 2013/02/11 22:15:45 wolf Exp $
#-------------------------------------------------------------------------------
# Aufruf:
# perl osmmerge.pl *.osm >result
#
# Verschmilzt beliebig viele OSM-Dateien.
# Bei gleichem Typ und gleicher Id wird das Objekt mit der hoechsten Version
# Sind auch die Versionen gleich, das Objekt aus der "linkesten" Datei.
#-------------------------------------------------------------------------------
use strict;
use utf8;
#-------------------------------------------------------------------------------
# Ausgabe in UTF-8
#-------------------------------------------------------------------------------
binmode STDOUT, ':utf8';
#-------------------------------------------------------------------------------
# Loese "*.ext" pattern auf und sammle die Dateinamen im array @name
#-------------------------------------------------------------------------------
my @name = ();
foreach my $arg (@ARGV) {
push (@name, glob($arg));
}
#-------------------------------------------------------------------------------
# Zur Kontrolle zeige die Liste der Dateien.
#-------------------------------------------------------------------------------
warn "Bearbeite Dateien: ", join (', ', @name), ".\n";
#-------------------------------------------------------------------------------
# Diese Arrays haben jeweils einen Eintrag je Eingabedatei
#-------------------------------------------------------------------------------
my @handle;
my @entry;
my @osmid;
my @version;
my $index;
#-------------------------------------------------------------------------------
# Je Eingabedatei
#-------------------------------------------------------------------------------
for ($index=0; $index<@name; $index++) {
#----------------------------------------------------------------------
# Oeffne die Datei und nehme als UTF-8 Codierung an
#----------------------------------------------------------------------
my $handle;
unless (open ($handle, '<:utf8', $name[$index])) {
#--------------------------------------------------------------
# Meldung wenn Oeffnen gescheitert
#--------------------------------------------------------------
warn "Kann Datei \"$name[$index]\" nicht oeffnen: $!\n";
#--------------------------------------------------------------
# Und Abbruch.
# Die "exit" Zeile kann auskommentiert werden, dann
# werden fehlende oder nicht lesbare Datein uebersprungen.
#--------------------------------------------------------------
exit 1;
}
#----------------------------------------------------------------------
# Datei geoeffnet. Lese das <?xml
#----------------------------------------------------------------------
$_ = <$handle>;
unless (m#<\?xml#) {
warn "Datei \"$name[$index]\": in erster Zeile kein \"<?xml\".\n";
exit 1;
}
#----------------------------------------------------------------------
# Lese das <osm
#----------------------------------------------------------------------
$_ = <$handle>;
unless (m#<osm#) {
warn "Datei \"$name[$index]\": in zweiter Zeile kein \"<osm\".\n";
exit 1;
}
#----------------------------------------------------------------------
# Speichere das Filehandle
#----------------------------------------------------------------------
$handle[$index] = $handle;
#----------------------------------------------------------------------
# Lese erstes Objekt
#----------------------------------------------------------------------
&readEntry ($index);
#----------------------------------------------------------------------
# Ueberspringe unbekannte Objekte
#----------------------------------------------------------------------
while ($entry[$index] !~ /^\s*<(changeset|node|way|relation)/) {
&readEntry ($index);
last if $entry[$index] eq '';
}
}
#-------------------------------------------------------------------------------
# Je Eingabedatei ein Element gelesen, also startbereit.
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# Header der Ausgabedatei
#-------------------------------------------------------------------------------
print "<?xml version='1.0' encoding='UTF-8'?>\n<osm version=\"0.6\" generator=\"osmmerge.pl\">\n";
#-------------------------------------------------------------------------------
# Bearbeite bis alle Eingabedateien voll bearbeitet sind.
#-------------------------------------------------------------------------------
for(;;) {
#-----------------------------------------------------------------------
# Finde die kleinste Id.
# Da mehrere Eingabedatein dieses Objekt enthalten koennen,
# sammle die Indizes dieser Dateien im Array @index.
#-----------------------------------------------------------------------
my @index;
#-----------------------------------------------------------------------
# Initialisiere "bisher kleinste gefundene Id" auf sehr hohen Wert
#-----------------------------------------------------------------------
my $osmid = '~';
#-----------------------------------------------------------------------
# Iteriere ueber die Eingabedateien:
#-----------------------------------------------------------------------
for ($index=0; $index<@name; $index++) {
#---------------------------------------------------------------
# Falls Objekt in Eingabedatei GROESSER ist als das kleinste
# bisher gefundene, ignoriere das Objekt
#---------------------------------------------------------------
next if $osmid[$index] gt $osmid;
#---------------------------------------------------------------
# Falls Objekt in Eingabedatei KLEINER ist als das kleinste
# bisher gefundene, merke dessen Id und verwerfe alle bisher
# gefundenen Indizes.
#---------------------------------------------------------------
if ($osmid[$index] lt $osmid) {
$osmid = $osmid[$index];
@index=();
}
#---------------------------------------------------------------
# Aspeichere aktuellen Index im Indexsammler.
#---------------------------------------------------------------
push (@index, $index);
}
#-----------------------------------------------------------------------
# Wenn kein Index gefunden, sind alle Dateien am Ende angelangt,
# und wir beenden die Schleife.
#-----------------------------------------------------------------------
last unless @index;
#-----------------------------------------------------------------------
# Suche die groesste Version und lade zu den gefundenen Indizes
# das naechste Objekt aus der jeweiligen Datein.
#
# version: bisher gefundene hoechste Version
# entry: das zugehoerige Objekt.
#-----------------------------------------------------------------------
my $version = -1;
my $entry;
#-----------------------------------------------------------------------
# Fuer alle Eintrage im Index:
#-----------------------------------------------------------------------
foreach $index (@index) {
#---------------------------------------------------------------
# Wenn die Version zum jeweiligen GROESSER ist als die
# groesste bisher bekannte, speichere diese Version
# und den zugehoerigen XML-Text.
#---------------------------------------------------------------
if ($version[$index]>$version) {
$version = $version[$index];
$entry = $entry[$index];
}
#---------------------------------------------------------------
# Sodann ueberschreibe das bearbeitete Element durch
# neu eingelesenes.
#---------------------------------------------------------------
readEntry($index);
}
#-----------------------------------------------------------------------
# Gebe den XML-Texte des Elementes mit der hoechsten Version aus.
#-----------------------------------------------------------------------
print $entry;
}
#-------------------------------------------------------------------------------
# Alle Eingabedateien bis zum Ende bearbeitet. Schliesse das "<osm>" ab.
#-------------------------------------------------------------------------------
print "</osm>\n";
exit 0;
#-------------------------------------------------------------------------------
# Lese das naechste Objekt zu einem bestimmten Index
#-------------------------------------------------------------------------------
sub readEntry {
#-----------------------------------------------------------------------
# Index aus Parameterliste
#-----------------------------------------------------------------------
my ($index) = @_;
#-----------------------------------------------------------------------
# Bestimme das Filehandle und lese die erste (oder einzige) Zeile
#-----------------------------------------------------------------------
my $handle = $handle[$index];
my $entry = <$handle>;
#-----------------------------------------------------------------------
# Ueberspringe Leerzeilen
#-----------------------------------------------------------------------
while ($entry =~ /^\s+$/) { $entry = <$handle>; }
#-----------------------------------------------------------------------
# Falls das Element in der Zeile NICHT beendet ist...
#-----------------------------------------------------------------------
unless (($entry =~ m#/>\s*$#) || ($entry =~ m#</\w+>\s*$#) || $entry eq '') {
#---------------------------------------------------------------
# Lese weitere Zeilen
#---------------------------------------------------------------
do {
$entry .= $_ = <$handle>;
} while ($_ && !m#^\s*</#);
#---------------------------------------------------------------
# bis das Ende-Element gefunden ist.
#---------------------------------------------------------------
}
#-----------------------------------------------------------------------
# Speichere den XML-Code des Objektes unter dem angegeben Index.
#-----------------------------------------------------------------------
$entry[$index]=$entry;
#-----------------------------------------------------------------------
# Ende der Datei-Marker, wenn keiner der erwarteten Typen gefunden.
#-----------------------------------------------------------------------
my $type = '~';
#-----------------------------------------------------------------------
# Bestimme den Objekt-Typ und ordne ihm einen Kennbuchstaben zu.
# Die Objekte sind zuerst nach Kennbuchstaben, dann nach Id sortiert.
#-----------------------------------------------------------------------
$type = "a" if $entry =~ /^\s*<changeset/;
$type = "b" if $entry =~ /^\s*<node/;
$type = "c" if $entry =~ /^\s*<way/;
$type = "d" if $entry =~ /^\s*<relation/;
#-----------------------------------------------------------------------
# Suchen den Id-Wert im XML: id="###" oder id='###'
# Die Id kann auch negativ sein.
#-----------------------------------------------------------------------
my $id = $entry =~ /id=["'](-?[1-9]\d*)["']/ ? $1 * 1.0 : 0;
#-----------------------------------------------------------------------
# Ich hoffe, dass maxbe das hier nicht sieht.
#-----------------------------------------------------------------------
# Konstruiere aus Typ und Id eine "osmid":
# Die Id wird mit einem Offset von 5*10^9 versehen,
# mit 10 Stellen und fuehrenden Nullen formatiert,
# und dann an den Typ angehaengt.
# Damit erzeugt ein Stringvergleich auf der "osmid"
# die gewuenschte Sortierreihenfolge.
#
#-----------------------------------------------------------------------
$osmid[$index]=sprintf '%s-%010.0f', $type, $id + 5e9;
#-----------------------------------------------------------------------
# Suchen den Versions-Wert im XML: version="###" oder version='###'
# Der Versionswert kann auch fehlen.
#-----------------------------------------------------------------------
$version[$index] = $entry =~ /version=["']([1-9]\d*)["']/ ? int $1 : 0;
}
#-------------------------------------------------------------------------------
# $Id: osmmerge.pl,v 1.7 2013/02/11 22:15:45 wolf Exp $
#-------------------------------------------------------------------------------
__END__
Have fun.
Gruß Wolf
Edit: jetzt auch grob ungehörige Quotes und überaus ungehörige negative ids und gänzlich ungehörige fehlende Versionsnummern und Leerzeilen und Kopfzeilen und was auch immer erlaubt. Und mit ein paar Zeilen Kommentar ergänzt.