[OverpassAPI/JavaScript] Relationsmitglieder aus JSON verarbeiten

Ich möchte eine vom Nutzer definierte Relation und ihre Member analysieren. Bisher habe ich es geschafft, die Relation zu laden und ihre Tags zu analysieren (z.B. relJSON[0].elements[0].tags.name). Nun möchte ich im Prinzip genauso mit ihren Mitgliedern weitermachen. Wenn ich mir mit (bzw. der OP-QL Entsprechung) ihre Angehörigen von der Overpass-API abfrage, habe ich das Problem, dass die Elemente in der JSON-Datei durcheinander sind und nur über die Kombination aus relJSON[0].elements[0].members[j].ref und subrelsJSON[0].elements[j].idnicht einander zugeordnet werden können. Wie kann ich eine Zuordnung so herstellen, dass ich die Daten sinnvoll weiterverarbeiten kann?

Das Ergebnis soll (erstmal) folgendes sein:

  • vom Nutzer angegebene Hauptrelation[list=*]

  • Unterrelation(en)[list=*]

  • Anzahl der verschiedenen Rollen

[/*] [/list][/*] [/list]

/e: Korrektur: …members[j].ref und …elements[j].id passen nicht zusammen. Wie ist das überhaupt gedacht?

Doch doch, genau so ist es gedacht, und genau so funktioniert es auch. Ich kenne jetzt nicht genau deine Query, aber was du wahrscheinlich nicht bedacht hast, ist, dass wenn du eine und ein über eine zusammenfasst, das Reihenfolge der Elemente i.d.R. durcheinander kommt. D.h., dass relJSON[0].elements[0] nicht der als Erstes über selektierten Hauptrelation entsprechen wird. Um das aber zu erreichen (ohne zwei getrennte API-Anfragen stellen zu müssen) verwendet man am Besten zwei Statements (siehe Beispiel unten). Zusätzlich musst du noch bedenken, dass die Hauptrelation ja auch noch ways oder nodes als members haben kann (die du ja nicht geladen hast). Dagegen hilft eine zusätzliche Abfrage auf relJSON[0].elements[0].members[j].type == “relation”.


<osm-script output="json">
  <id-query type="relation" ref="2171699" />
  <print mode="body"/>
  <recurse type="relation-relation"/>
  <print mode="body" order="id"/>
</osm-script>

Mein Fehler war nahe da dran: Ich lasse die Hauptrelation zuvor schon in einer eigenen Anfrage übermitteln, habe dann aber vor Ausgabe der Relationsliste das Objekt mit dem neuen Überschrieben und damit natürlich die falschen OSM-IDs ausgegeben. Dank deines Tipps mit dem zweiten out; kommen die IDs jetzt in beiden Listen vor. Nur bei der Zuordung habe ich wohl noch ein Verständnisproblem.

Kann ich irgendwie einfacher die verschachtelten Elemente erhalten als bei jedem Objekt alle Objekte durchzugehen bis das richtige dabei ist? Sowas wie z.B. VVrelJSON[0].elements[0].members[j].tags.name wäre super (dabei dann mit nur einem VVrelJSON[0].elements) - kann man die OP-API sowas ausgeben lassen?

Danke für den Hinweis. Die Hauptrelation enthält in dem Fall, für den ich das schreibe zwar keine Nodes oder Ways, aber theoretisch möglich wäre es natürlich und wird auch bei “niedrigeren” Relationen vorkommen, für die ich soweit möglich den selben Code nutzen möchte.

mfg~ray

P.S.: Falls jemand genau wissen will was ich mache hier der JS-Teil meines Quelltextes (noch ohne OSM-Objekt-Typ-Prüfung):

<script type="text/javascript">
		var page = {
			basetitle: "Seitentitel"
		};
		var Overpass = {
			APIs: [
				{
					name: "overpass-api.de",
					baseURI: "http://www.overpass-api.de/api/interpreter?"
				},
				{
					name: "rambler.ru",
					baseURI: "http://overpass.osm.rambler.ru/cgi/interpreter?"
				},
				{
					name: "osm.fr",
					baseURI: "http://api.openstreetmap.fr/oapi/interpreter?"
				}
			],
			activeAPI: 0,
			performRequest: null,	// Prototyp for Function
			getObjById: null,		// Prototyp for Function
			getRelMembers: null		// Prototyp for Function
		};
		var VVrelJSON = "";
		
		Overpass.performRequest = function (request) {
			var xhr = new XMLHttpRequest({ mozAnon: true, mozSystem: true });
			xhr.open("GET", Overpass.APIs[Overpass.activeAPI].baseURI + "data=[out:json];" + request + "out;", false);
			/* Eventlistener for xhr: */
			xhr.send();
			try {
				//alert(xhr.responseText);
				document.getElementById("debugview").innerHTML = document.getElementById("debugview").innerHTML + "<br/><br/><br/><br/><br/>" + xhr.responseText;
				return eval("[" + xhr.responseText + "]");
			}
			catch(e) {
				document.getElementsByTagName("body")[0].innerHTML = document.getElementsByTagName("body")[0].innerHTML + "<div class=\"error\">Die Antwort des Overpass-Servers ist ungültig. Die Antwort ist: <div class=\"code\">" + xhr.responseText + "</div></div>";
				return null;
			}
		}
		Overpass.getObjById = function (type, ID){
			return Overpass.performRequest(type + "(" + ID + ");");
		}
		Overpass.getRelWithMembers = function (RelID){
			return Overpass.performRequest("relation(" + RelID + ")->.ursprung;.ursprung out;(rel(r.ursprung);way(r.ursprung);node(r.ursprung););");
		}
		
		function init() {
			document.title = page.basetitle;
			document.getElementById("buttonParseVVrel").disabled=true;
		}
		
		function recieveVVrel() {
			if (!isNaN(document.getElementById("inputVVsearch").value)) {
				VVrelJSON = Overpass.getObjById("relation", document.getElementById("inputVVsearch").value);
			} else {
				VVrelJSON = Overpass.performRequest("(relation[public_transport=network]" +
					"[abbreviation=\"" + document.getElementById("inputVVsearch").value + "\"];" +
					"relation[public_transport=network]" + "[name=\"" + document.getElementById("inputVVsearch").value +
				"\"];);");
			}
			
			document.title = page.basetitle + ": " + VVrelJSON[0].elements[0].tags.name;
			document.getElementById("basedata-VVname").innerHTML = VVrelJSON[0].elements[0].tags.name + " (" + VVrelJSON[0].elements[0].tags.abbreviation + ")";
			document.getElementById("buttonParseVVrel").disabled=false;
		}
		
		function parseVVrel() {
			VVrelJSON = Overpass.getRelWithMembers(VVrelJSON[0].elements[0].id);
			for (var i=0; i<VVrelJSON[0].elements[0].members.length; i++) {
				var element = document.createElement("li");
				document.getElementById("VVcontent").appendChild(element);
				element.innerHTML = VVrelJSON[0].elements[0].members[i].ref + " - " +
					VVrelJSON[0].elements[i].id + " (" +
					VVrelJSON[0].elements[i].tags.type + ": " +
					VVrelJSON[0].elements[i].tags.name + ")";
			}
		}
	</script>