1 /*
2 SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7 #include "xmlwriter.h"
8 #include "datatypes.h"
9 #include "element.h"
10
11 #include <QXmlStreamWriter>
12
13 using namespace OSM;
14
15 template <typename T>
writeTags(QXmlStreamWriter & writer,const T & elem)16 static void writeTags(QXmlStreamWriter &writer, const T &elem)
17 {
18 for (const auto &tag : elem.tags) {
19 writer.writeStartElement(QStringLiteral("tag"));
20 writer.writeAttribute(QStringLiteral("k"), QString::fromUtf8(tag.key.name()));
21 writer.writeAttribute(QStringLiteral("v"), QString::fromUtf8(tag.value));
22 writer.writeEndElement();
23 }
24 }
25
write(const DataSet & dataSet,QIODevice * out)26 void XmlWriter::write(const DataSet &dataSet, QIODevice *out)
27 {
28 QXmlStreamWriter writer(out);
29 writer.setAutoFormatting(true);
30 writer.setAutoFormattingIndent(-1);
31
32 writer.writeStartDocument();
33 // using \123 instead of 'S' here prevents reuse lint from interpreting the following string as a license header for this file
34 writer.writeComment(QStringLiteral("\n \123PDX-FileCopyrightText: OpenStreetMap contributors\n \123PDX-License-Identifier: ODbL-1.0\n"));
35 writer.writeStartElement(QStringLiteral("osm"));
36 writer.writeAttribute(QStringLiteral("version"), QStringLiteral("0.6"));
37 writer.writeAttribute(QStringLiteral("generator"), QStringLiteral("KOSM"));
38
39 OSM::BoundingBox bbox;
40 OSM::for_each(dataSet, [&bbox](auto elem) { bbox = OSM::unite(bbox, elem.boundingBox()); });
41 writer.writeStartElement(QStringLiteral("bounds"));
42 writer.writeAttribute(QStringLiteral("minlat"), QString::number(bbox.min.latF(), 'f', 10));;
43 writer.writeAttribute(QStringLiteral("minlon"), QString::number(bbox.min.lonF(), 'f', 10));;
44 writer.writeAttribute(QStringLiteral("maxlat"), QString::number(bbox.max.latF(), 'f', 10));;
45 writer.writeAttribute(QStringLiteral("maxlon"), QString::number(bbox.max.lonF(), 'f', 10));;
46 writer.writeEndElement();
47
48 for (const auto &node : dataSet.nodes) {
49 writer.writeStartElement(QStringLiteral("node"));
50 writer.writeAttribute(QStringLiteral("id"), QString::number(node.id));
51 writer.writeAttribute(QStringLiteral("lat"), QString::number(node.coordinate.latF(), 'f', 10));
52 writer.writeAttribute(QStringLiteral("lon"), QString::number(node.coordinate.lonF(), 'f', 10));
53 writeTags(writer, node);
54 writer.writeEndElement();
55 }
56
57 for (const auto &way : dataSet.ways) {
58 writer.writeStartElement(QStringLiteral("way"));
59 writer.writeAttribute(QStringLiteral("id"), QString::number(way.id));
60 for (const auto &nd : way.nodes) {
61 writer.writeStartElement(QStringLiteral("nd"));
62 writer.writeAttribute(QStringLiteral("ref"), QString::number(nd));
63 writer.writeEndElement();
64 }
65 writeTags(writer, way);
66 writer.writeEndElement();
67 }
68
69 for (const auto &rel : dataSet.relations) {
70 writer.writeStartElement(QStringLiteral("relation"));
71 writer.writeAttribute(QStringLiteral("id"), QString::number(rel.id));
72 for (const auto &mem : rel.members) {
73 writer.writeStartElement(QStringLiteral("member"));
74 switch (mem.type()) {
75 case OSM::Type::Null: Q_UNREACHABLE();
76 case OSM::Type::Node: writer.writeAttribute(QStringLiteral("type"), QStringLiteral("node")); break;
77 case OSM::Type::Way: writer.writeAttribute(QStringLiteral("type"), QStringLiteral("way")); break;
78 case OSM::Type::Relation: writer.writeAttribute(QStringLiteral("type"), QStringLiteral("relation")); break;
79 }
80 writer.writeAttribute(QStringLiteral("ref"), QString::number(mem.id));
81 if (!mem.role().isNull()) {
82 writer.writeAttribute(QStringLiteral("role"), QString::fromUtf8(mem.role().name()));
83 }
84 writer.writeEndElement();
85 }
86 writeTags(writer, rel);
87 writer.writeEndElement();
88 }
89
90 writer.writeEndElement();
91 writer.writeEndDocument();
92 }
93