Skip to content

Instantly share code, notes, and snippets.

@zdila
Created December 7, 2022 17:43
Show Gist options
  • Save zdila/102249386a8143ad45188a12c1ec7714 to your computer and use it in GitHub Desktop.
Save zdila/102249386a8143ad45188a12c1ec7714 to your computer and use it in GitHub Desktop.
OSM move waterway tags to parent relations
/*
Overpass QL for the input file (waterway-rels.osm):
```
[out:xml][timeout:90];
{{geocodeArea:slovakia}}->.searchArea;
(
relation["type"="waterway"](area.searchArea);
);
(._;>;);
out meta;
```
*/
const fs = require("fs");
const xml2js = require("xml2js");
let data;
xml2js.parseString(fs.readFileSync("waterway-rels.osm"), (err, result) => {
data = result;
});
const wayMap = new Map();
for (const way of data.osm.way) {
wayMap.set(way.$.id, way);
}
rel: for (const relation of data.osm.relation) {
const tags = tagsToMap(relation);
const members = ensureArray(relation.member);
const ways = members
.filter((member) => member.$.type === "way")
.map((member) => wayMap.get(member.$.ref));
let modifyRel = false;
for (const way of ways) {
let conflict = false;
for (const tag of ensureArray(way.tag)) {
const key = tag.$.k;
const value = tag.$.v;
if (
key.startsWith("name:") ||
key.endsWith("_name") ||
key === "wikipedia" ||
key === "wikidata" ||
key === "ref" ||
key === "destination"
) {
if (!tags[key]) {
tags[key] = value;
modifyRel = true;
} else if (tags[key] !== value) {
console.error(
`Conflict! "${key}"="${tags[key]}" vs "${value}" r${relation.$.id} w${way.$.id}`
);
conflict = true;
}
}
}
if (conflict) {
continue rel;
}
}
for (let i = 0; i < ways.length; i++) {
const way = ways[i];
const tagArray = ensureArray(way.tag);
for (let j = tagArray.length - 1; j >= 0; j--) {
const tag = tagArray[j];
const key = tag.$.k;
const value = tag.$.v;
if (
key.startsWith("name:") ||
key.endsWith("_name") ||
key === "wikipedia" ||
key === "wikidata" ||
key === "ref" ||
key === "destination"
) {
way.$.action = "modify";
tagArray.splice(j, 1);
}
}
}
if (modifyRel) {
relation.$.action = "modify";
relation.tag = Object.entries(tags).map(([k, v]) => ({
$: {
k,
v,
},
}));
}
}
const builder = new xml2js.Builder();
console.log(builder.buildObject(data));
function tagsToMap(a) {
const tags = {};
for (const tag of ensureArray(a.tag)) {
tags[tag.$.k] = tag.$.v;
}
return tags;
}
function ensureArray(a) {
return !a ? [] : Array.isArray(a) ? a : [a];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment