Overpass: Ländercode zu Städten abfragen

Ich möchte gerne zu einer trivialen Overpass-Query gerne ergänzen, dass zu jeder Stadt im Ergebnis noch der Ländercode (Tag: ISO3166-1) im Ergebnis ergänzt wird. Leider fehlt mir hier mangels Overpass-Kompetenz jeglicher Ansatz.

Wer kann helfen?

Suchst du eventuell nach einer umgebenden boundary relation mit admin_level=1?

Ja, die suche ich. Allerdings brauche ich nicht die Geometrie sondern nur ein Tag der umgebenden boundary relation.

[out:csv(name, ::id,::type,"ISO3166-1")][timeout:25];
// gather results
nwr["place"="city"]({{bbox}});
// print results
foreach
  {  out;
     is_in;
     area._[admin_level="2"];  
     out;
  }

Link mit bbox: https://overpass-turbo.eu/s/1Scx
funktioniert für alle nodes, aber nicht für relations.
Das Ergebnis sieht so aus:

name	@id	@type	ISO3166-1
Bern	18477455	node	
Schweiz/Suisse/Svizzera/Svizra	3600051701	area	CH
Mulhouse	26686568	node	
France	3602202162	area	FR
France (terres)	3616467322	area	
Basel	27284711	node	
Schweiz/Suisse/Svizzera/Svizra	3600051701	area	CH
Freiburg im Breisgau	240092010	node	
Deutschland	3600051477	area	DE
Deutschland (Landmasse)	3600062781	area	
Zürich	240025182	node	
Schweiz/Suisse/Svizzera/Svizra	3600051701	area	CH
Winterthur	1378949424	node	
Schweiz/Suisse/Svizzera/Svizra	3600051701	area	CH
Biel/Bienne	1682380	relation	
Zürich	1682248	relation	

Das ist ja hervorragend!

Lässt sich das auch mit JSON-output kombinieren, ohne, dass alle Länder-Tags für jede Stadt wiederholt werden?

Jetzt tun auch die rels:
https://overpass-turbo.eu/s/1Sd6

Bei json kann man mWn keine Auswahl bezüglich der Ausgabe treffen.
Aber vielleicht kannst Du analog zu
https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_API_by_Example#Wiki_table_generator_(since_0.7.54)
etwas basteln.

Das wird ja immer besser!

Ich habe ein wenig mit dem convert-Statement experimentiert, allerdings scheint es so zu sein, dass man auch damit leider keine zwei Elemente verschmelzen kann.

Man kann mit einem Texteditor (z.B. Word) aus den zwei Zeilen eine machen:
Suchen nach: relation^t^p
Ersetzen durch: relation^t

analog: node^t^p

name	@id	@type	ISO3166-1
Bern	18477455	node 	Schweiz/Suisse/Svizzera/Svizra	3600051701	area	CH
Mulhouse	26686568	node 	France	3602202162	area	FR
Basel	27284711	node 	Schweiz/Suisse/Svizzera/Svizra	3600051701	area	CH
Freiburg im Breisgau	240092010	node 	Deutschland	3600051477	area	DE
Zürich	240025182	node 	Schweiz/Suisse/Svizzera/Svizra	3600051701	area	CH
Winterthur	1378949424	node 	Schweiz/Suisse/Svizzera/Svizra	3600051701	area	CH
Biel/Bienne	1682380	relation	Schweiz/Suisse/Svizzera/Svizra	3600051701	area	CH
Zürich	1682248	relation	Schweiz/Suisse/Svizzera/Svizra	3600051701	area	CH

Du kannst auch noch aus dem csv Befehl ::id,::type rauswerfen.

Ich denke, ich habe einen Weg gefunden, wie ich ein Element erweitern kann, scheitere jetzt aber einem Detail der Syntax:

nwr({{bbox}})[place=city]->.cities;
  foreach .cities -> .city (
    .city .is_in->.administrative;
    area.administrative[name][boundary=administrative][admin_level=2] -> .country;
    .city convert city_copy ::=::,
              ::id = id(),
              ::geom = geom(),
              is_in=.country(t["name"]) -> .augmented;
   
    .augmented out;
  );

Hier gibt es ein Beispiel, das etwas Ähnliches macht:
https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_API_by_Example
nach “Adding Georeference details” suchen.

Mit etwas Probieren, bin ich darauf gekommen:

[out:json][timeout:25];
node({{bbox}})[place=city];
  foreach (
    is_in->.a;
    area.a[name][boundary=administrative][admin_level=2] -> .a;
    convert node name = _.set(t["name"]),
              ::id = id(),
              is_in = a.set("{" + t["name"] + ":" + t["ISO3166-1"] +"}");      
    out;
  );

oder
https://overpass-turbo.eu/s/1Sdz

Funktioniert nur für nodes, Erweiterung auf rel wahrscheinlich möglich wie vorne.

Das funktioniert hevorragend. Ich habe es angepasst, sodass es nodes, ways und relationen nimmt:

[out:json][timeout:25];
nwr({{bbox}})[place=city];
  foreach (
    is_in->.a;
    area.a[name][boundary=administrative][admin_level=2] -> .a;
    convert node name = _.set(t["name"]),
              ::id = id(),
              is_in = a.set("{" + t["name"] + ":" + t["ISO3166-1"] +"}");      
    out;
  );

Knackpunkt ist jetzt, vermute ich, dass is_in eine Koordinate möchte Nodes direkt verarbeitet. Ich habe gesehen, dass es eine Methode center() gibt, komme aber auch mit Experimentieren nicht drauf, wie ich den Mittelpunkt des aktuelle Elements der Schleife mit Hilfe von center() an is_in übergebe, sodass es für Nodes, Ways und Relations gleichermaßen funktioniert.

Der Ansatz in der früheren Version:

rel["place"="city"]({{bbox}});
foreach
  {  out;
   way(r); 
   node(w);
    is_in;

hat funktioniert, weil alle Punkte der Relation in einem Staat liegen.

Hier tut das zwar auch, man erhält aber für jeden Punkt in der Relation (und das sind bei ZH viele) einen Punkt in der Ausgabe.
Wie cent() funktioniert, verstehe ich auch nicht.