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