|
/* |
|
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]; |
|
} |