File indexing completed on 2024-11-24 04:46:23
0001 /* 0002 SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "xmlparser.h" 0008 #include "datatypes.h" 0009 0010 #include <QIODevice> 0011 #include <QXmlStreamReader> 0012 0013 using namespace OSM; 0014 0015 XmlParser::XmlParser(DataSet* dataSet) 0016 : m_dataSet(dataSet) 0017 { 0018 assert(dataSet); 0019 } 0020 0021 void XmlParser::parse(QIODevice *io) 0022 { 0023 QXmlStreamReader reader(io); 0024 while (!reader.atEnd()) { 0025 const auto token = reader.readNext(); 0026 if (token != QXmlStreamReader::StartElement) { 0027 continue; 0028 } 0029 0030 if (reader.name() == QLatin1StringView("node")) { 0031 parseNode(reader); 0032 } else if (reader.name() == QLatin1StringView("way")) { 0033 parseWay(reader); 0034 } else if (reader.name() == QLatin1StringView("relation")) { 0035 parseRelation(reader); 0036 } else if (reader.name() == QLatin1StringView("remark")) { 0037 m_error = reader.readElementText(); 0038 return; 0039 } 0040 } 0041 } 0042 0043 void XmlParser::parseNode(QXmlStreamReader &reader) 0044 { 0045 Node node; 0046 node.id = reader.attributes().value(QLatin1StringView("id")).toLongLong(); 0047 node.coordinate = Coordinate( 0048 reader.attributes().value(QLatin1StringView("lat")).toDouble(), 0049 reader.attributes().value(QLatin1String("lon")).toDouble()); 0050 0051 while (!reader.atEnd() && reader.readNext() != QXmlStreamReader::EndElement) { 0052 if (reader.tokenType() != QXmlStreamReader::StartElement) { 0053 continue; 0054 } 0055 if (reader.name() == QLatin1StringView("tag")) { 0056 parseTag(reader, node); 0057 } 0058 reader.skipCurrentElement(); 0059 } 0060 0061 m_dataSet->addNode(std::move(node)); 0062 } 0063 0064 void XmlParser::parseWay(QXmlStreamReader &reader) 0065 { 0066 Way way; 0067 way.id = reader.attributes().value(QLatin1StringView("id")).toLongLong(); 0068 0069 while (!reader.atEnd() && reader.readNext() != QXmlStreamReader::EndElement) { 0070 if (reader.tokenType() != QXmlStreamReader::StartElement) { 0071 continue; 0072 } 0073 if (reader.name() == QLatin1StringView("nd")) { 0074 OSM::Id node; 0075 node = 0076 reader.attributes().value(QLatin1StringView("ref")).toLongLong(); 0077 way.nodes.push_back(node); 0078 } else if (reader.name() == QLatin1StringView("tag")) { 0079 parseTagOrBounds(reader, way); 0080 } else if (reader.name() == QLatin1StringView("bounds")) { 0081 parseBounds(reader, way); 0082 } 0083 reader.skipCurrentElement(); 0084 } 0085 0086 m_dataSet->addWay(std::move(way)); 0087 } 0088 0089 void XmlParser::parseRelation(QXmlStreamReader &reader) 0090 { 0091 Relation rel; 0092 rel.id = reader.attributes().value(QLatin1StringView("id")).toLongLong(); 0093 0094 while (!reader.atEnd() && reader.readNext() != QXmlStreamReader::EndElement) { 0095 if (reader.tokenType() != QXmlStreamReader::StartElement) { 0096 continue; 0097 } 0098 if (reader.name() == QLatin1StringView("tag")) { 0099 parseTagOrBounds(reader, rel); 0100 } else if (reader.name() == 0101 QLatin1StringView("bounds")) { // Overpass style bounding box 0102 parseBounds(reader, rel); 0103 } else if (reader.name() == QLatin1StringView("member")) { 0104 Member member; 0105 member.id = 0106 reader.attributes().value(QLatin1StringView("ref")).toLongLong(); 0107 const auto type = 0108 reader.attributes().value(QLatin1StringView("type")); 0109 if (type == QLatin1StringView("node")) { 0110 member.type = Type::Node; 0111 } else if (type == QLatin1StringView("way")) { 0112 member.type = Type::Way; 0113 } else { 0114 member.type = Type::Relation; 0115 } 0116 member.role = 0117 reader.attributes() 0118 .value(QLatin1StringView("role")) 0119 .toString(); // TODO shared value pool for these values 0120 rel.members.push_back(std::move(member)); 0121 } 0122 reader.skipCurrentElement(); 0123 } 0124 0125 m_dataSet->addRelation(std::move(rel)); 0126 } 0127 0128 template <typename T> 0129 void XmlParser::parseTag(QXmlStreamReader &reader, T &elem) 0130 { 0131 OSM::setTagValue(elem, 0132 reader.attributes().value(QLatin1StringView("k")).toString(), 0133 reader.attributes().value(QLatin1String("v")).toString()); 0134 } 0135 0136 template <typename T> 0137 void XmlParser::parseTagOrBounds(QXmlStreamReader &reader, T &elem) 0138 { 0139 if (reader.attributes().value(QLatin1StringView("k")) == 0140 QLatin1String("bBox")) { // osmconvert style bounding box 0141 const auto v = reader.attributes() 0142 .value(QLatin1StringView("v")) 0143 .split(QLatin1Char(',')); 0144 if (v.size() == 4) { 0145 elem.bbox.min = Coordinate(v[1].toDouble(), v[0].toDouble()); 0146 elem.bbox.max = Coordinate(v[3].toDouble(), v[2].toDouble()); 0147 } 0148 } else { 0149 parseTag(reader, elem); 0150 } 0151 } 0152 0153 template<typename T> 0154 void XmlParser::parseBounds(QXmlStreamReader &reader, T &elem) 0155 { 0156 // overpass style bounding box 0157 elem.bbox.min = Coordinate( 0158 reader.attributes().value(QLatin1StringView("minlat")).toDouble(), 0159 reader.attributes().value(QLatin1String("minlon")).toDouble()); 0160 elem.bbox.max = Coordinate( 0161 reader.attributes().value(QLatin1StringView("maxlat")).toDouble(), 0162 reader.attributes().value(QLatin1String("maxlon")).toDouble()); 0163 } 0164 0165 QString XmlParser::error() const 0166 { 0167 return m_error; 0168 }