Anleitung

Overpass: «does not support the diff or adiff mode»

Warum eine Verlaufsabfrage mit [diff:] oder [adiff:] mit JSON- oder CSV-Ausgabe scheitert, und zwei Wege zu den Änderungen.

Overpass schreibt Diffs nur als XML. Entfernen Sie [out:json] oder [out:csv(…)] aus einer Abfrage mit [diff:] oder [adiff:], oder schreiben Sie [out:xml], und lesen Sie das XML. Braucht Ihr Code JSON, führen Sie die Abfrage für jedes Datum einmal mit [date:] aus und vergleichen Sie die beiden Antworten nach Typ, ID und Version.

Der Fehler

[out:json][adiff:"2024-01-01T00:00:00Z","2025-01-01T00:00:00Z"];
nwr(47.3693,8.5385,47.3707,8.5405)(if:t["amenity"]=="restaurant");
out meta;

Overpass lehnt diese Abfrage ab, bevor sie läuft, mit HTTP 400 und einer HTML-Seite mit diesem Text:

Error: line 1: static error: The selected output format does not support the diff or adiff mode.

[out:csv(…)] erhält dieselbe Antwort. Ein Diff ist eine Liste von <action>-Elementen mit einer alten und einer neuen Version, und nur die XML-Ausgabe hat dafür eine Form.

Lösung 1: das XML lesen

Schreiben Sie [out:xml], oder lassen Sie die Einstellung out weg; XML ist der Standard. Python liest die Antwort mit xml.etree.ElementTree aus der Standardbibliothek:

import xml.etree.ElementTree as ET

root = ET.fromstring(answer)            # die Bytes der Antwort
for action in root.findall("action"):
    old, new = action.find("old/*"), action.find("new/*")
    print(action.get("type"), (new if new is not None else action[0]).get("id"))

Jede Aktion ist create, modify oder delete. Bei [adiff:] ist ein delete, dessen neue Version visible="false" hat, ein gelöschtes Element, und eines mit visible="true" gibt es noch, es passt aber nicht mehr zur Abfrage. Änderungen in OpenStreetMap zwischen zwei Daten enthält das ganze Skript.

Lösung 2: zwei Abfragen in JSON

Führen Sie dieselbe Abfrage mit [date:] für jedes der beiden Daten aus und vergleichen Sie die Elemente. Mit out meta hat jedes Element seine Version, eine Bearbeitung zeigt sich also als andere Version:

import json
import os
import urllib.parse
import urllib.request

URL = "https://api.overpass.ch/v1/" + os.environ["OVERPASS_CH_KEY"] + "/interpreter"
QUERY = """[out:json][timeout:60][date:"{date}"];
nw(47.369,8.541,47.376,8.547)(if:t["amenity"]=="restaurant");
out meta center;"""


def at(date):
    data = urllib.parse.urlencode({"data": QUERY.format(date=date)}).encode()
    els = json.loads(urllib.request.urlopen(URL, data=data, timeout=90).read())["elements"]
    return {(e["type"], e["id"]): e for e in els}


a, b = at("2023-01-01T00:00:00Z"), at("2025-01-01T00:00:00Z")
for k in sorted(b.keys() - a.keys()):
    print("added   ", b[k]["tags"].get("name", k))
for k in sorted(a.keys() - b.keys()):
    print("removed ", a[k]["tags"].get("name", k))
edited = [k for k in a.keys() & b.keys() if a[k]["version"] != b[k]["version"]]
print(len(edited), "edited,", len(a.keys() & b.keys()) - len(edited), "unchanged")
added    Da Raffaele
added    Rank
added    Rank
added    Wien Zeile
added    Rising Sun
added    Hirschli
added    roots
added    Restaurant zum weissen Kreuz
removed  Enzian vegan food
removed  Isebähnli
removed  The Butcher
removed  Kormasutra
removed  Öpfelchammer
removed  barfüsser
removed  Bauernschänke
removed  Long Wai
removed  ('node', 9270127717)
removed  ('node', 9870177417)
61 edited, 4 unchanged

Die Restaurants im Zürcher Niederdorf von 2023 bis 2025. Beide Abfragen zusammen dauerten 2,9 Sekunden. Die Summen sind die der Abfrage mit [adiff:] über dasselbe Gebiet, aber dieser Weg kann ein gelöschtes Restaurant nicht von einem unterscheiden, das jetzt etwas anderes ist: Beide fehlen am zweiten Datum. Um es herauszufinden, fragen Sie die fehlenden IDs am zweiten Datum ab, oder verwenden Sie [adiff:].

Gut zu wissen

  • [date:] allein funktioniert mit jedem Ausgabeformat, auch JSON und CSV. Nur [diff:] und [adiff:] brauchen XML.
  • Der Verlauf beginnt am 12. September 2012. Ein Datum davor liefert nur die Elemente, die seither niemand bearbeitet hat.
  • out meta fügt Version, Zeit und Benutzer jedes Elements hinzu; ohne diese Angabe hat der JSON-Vergleich oben keine Versionen zum Vergleichen.

Bei overpass.ch

Verlaufsabfragen gehören zu den Tarifen Medium und Large; andere Tarife erhalten HTTP 403 history_not_in_plan. Overpass-Verlaufsabfragen erklärt [date:], [diff:] und [adiff:] mit Beispielen.