diff options
author | Sergey Yershov <yershov@corp.mail.ru> | 2015-08-11 16:05:52 +0300 |
---|---|---|
committer | Alex Zolotarev <alex@maps.me> | 2015-09-23 03:01:19 +0300 |
commit | cd6c2837830857381ec91b0578cbf1593ac51ed5 (patch) | |
tree | 88b68eb3d6bc311c4aadbc713ad77db4ce32ea0d /generator | |
parent | 07f90e34cb993a4430ab8ac865a08e2096336b92 (diff) |
Refactor creating XMLElement
Diffstat (limited to 'generator')
-rw-r--r-- | generator/first_pass_parser.hpp | 72 | ||||
-rw-r--r-- | generator/generator.pro | 1 | ||||
-rw-r--r-- | generator/generator_tests/osm_o5m_source_test.cpp | 4 | ||||
-rw-r--r-- | generator/generator_tests/source_to_element_test.cpp | 41 | ||||
-rw-r--r-- | generator/osm2type.cpp | 4 | ||||
-rw-r--r-- | generator/osm_element.hpp | 24 | ||||
-rw-r--r-- | generator/osm_o5m_source.hpp | 11 | ||||
-rw-r--r-- | generator/osm_source.cpp | 162 | ||||
-rw-r--r-- | generator/osm_source.hpp | 7 | ||||
-rw-r--r-- | generator/xml_element.cpp | 143 | ||||
-rw-r--r-- | generator/xml_element.hpp | 183 |
11 files changed, 337 insertions, 315 deletions
diff --git a/generator/first_pass_parser.hpp b/generator/first_pass_parser.hpp deleted file mode 100644 index 719e45a303..0000000000 --- a/generator/first_pass_parser.hpp +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include "generator/xml_element.hpp" -#include "generator/osm_decl.hpp" - -#include "indexer/mercator.hpp" - -#include "base/string_utils.hpp" - - -template <class THolder> -class FirstPassParser : public BaseOSMParser -{ - THolder & m_holder; - -public: - FirstPassParser(THolder & holder) : m_holder(holder) - { - } - -protected: - virtual void EmitElement(XMLElement * p) - { - if (p->tagKey == XMLElement::ET_NODE) - { - // store point - - // convert to mercator - p->lat = MercatorBounds::LatToY(p->lat); - p->lon = MercatorBounds::LonToX(p->lon); - - m_holder.AddNode(p->id, p->lat, p->lon); - } - else if (p->tagKey == XMLElement::ET_WAY) - { - // store way - WayElement way(p->id); - - for (auto const & e: p->childs) - if (e.tagKey == XMLElement::ET_ND) - way.nodes.push_back(e.ref); - - if (way.IsValid()) - m_holder.AddWay(p->id, way); - } - else if (p->tagKey == XMLElement::ET_RELATION) - { - // store relation - - RelationElement relation; - for (auto const & e: p->childs) - { - if (e.tagKey == XMLElement::ET_MEMBER) - { - if (e.type == "node") - relation.nodes.push_back(make_pair(e.ref, e.role)); - else if (e.type == "way") - relation.ways.push_back(make_pair(e.ref, e.role)); - // we just ignore type == "relation" - } - else if (e.tagKey == XMLElement::ET_TAG) - { - // relation tags writing as is - relation.tags.insert(make_pair(e.k, e.v)); - } - } - - if (relation.IsValid()) - m_holder.AddRelation(p->id, relation); - } - } -}; diff --git a/generator/generator.pro b/generator/generator.pro index f64455cb40..3db8b861ab 100644 --- a/generator/generator.pro +++ b/generator/generator.pro @@ -47,7 +47,6 @@ HEADERS += \ feature_generator.hpp \ feature_merger.hpp \ feature_sorter.hpp \ - first_pass_parser.hpp \ gen_mwm_info.hpp \ generate_info.hpp \ osm2meta.hpp \ diff --git a/generator/generator_tests/osm_o5m_source_test.cpp b/generator/generator_tests/osm_o5m_source_test.cpp index e87cb7e354..da312cdec3 100644 --- a/generator/generator_tests/osm_o5m_source_test.cpp +++ b/generator/generator_tests/osm_o5m_source_test.cpp @@ -32,8 +32,8 @@ UNIT_TEST(OSM_O5M_Source_Node_read_test) CHECK_EQUAL(em.uid, 395071, ()); CHECK_EQUAL(em.version, 8, ()); CHECK_EQUAL(em.changeset, 12059128, ()); - CHECK_EQUAL(em.lon, 387666704, ()); - CHECK_EQUAL(em.lat, 550927062, ()); + CHECK_EQUAL(em.lon, 38.7666704, ()); + CHECK_EQUAL(em.lat, 55.0927062, ()); auto const & tags = em.Tags(); auto tagIterator = tags.begin(); diff --git a/generator/generator_tests/source_to_element_test.cpp b/generator/generator_tests/source_to_element_test.cpp index 15e8ac4db1..2dd97cf0a4 100644 --- a/generator/generator_tests/source_to_element_test.cpp +++ b/generator/generator_tests/source_to_element_test.cpp @@ -14,24 +14,16 @@ #include "source_data.hpp" -struct DummyParser : public BaseOSMParser -{ - vector<XMLElement> & m_e; - DummyParser(vector<XMLElement> & e) : BaseOSMParser() , m_e(e) {} - void EmitElement(XMLElement * p) override - { - m_e.push_back(*p); - } -}; - UNIT_TEST(Source_To_Element_create_from_xml_test) { istringstream ss(way_xml_data); SourceReader reader(ss); vector<XMLElement> elements; - DummyParser parser(elements); - ParseXMLSequence(reader, parser); + BuildFeaturesFromXML(reader, [&elements](XMLElement * e) + { + elements.push_back(*e); + }); TEST_EQUAL(elements.size(), 10, (elements)); } @@ -43,8 +35,10 @@ UNIT_TEST(Source_To_Element_create_from_o5m_test) SourceReader reader(ss); vector<XMLElement> elements; - DummyParser parser(elements); - BuildFeaturesFromO5M(reader, parser); + BuildFeaturesFromO5M(reader, [&elements](XMLElement * e) + { + elements.push_back(*e); + }); TEST_EQUAL(elements.size(), 10, (elements)); } @@ -54,16 +48,25 @@ UNIT_TEST(Source_To_Element_check_equivalence) SourceReader readerXML(ss1); vector<XMLElement> elementsXML; - DummyParser parserForXML(elementsXML); - ParseXMLSequence(readerXML, parserForXML); + BuildFeaturesFromXML(readerXML, [&elementsXML](XMLElement * e) + { + elementsXML.push_back(*e); + }); string src(begin(relation_o5m_data), end(relation_o5m_data)); istringstream ss2(src); SourceReader readerO5M(ss2); vector<XMLElement> elementsO5M; - DummyParser parserForO5M(elementsO5M); - BuildFeaturesFromO5M(readerO5M, parserForO5M); + BuildFeaturesFromO5M(readerO5M, [&elementsO5M](XMLElement * e) + { + elementsO5M.push_back(*e); + }); + + TEST_EQUAL(elementsXML.size(), elementsO5M.size(), ()); - TEST_EQUAL(elementsXML, elementsO5M, ()); + for (size_t i = 0; i < elementsO5M.size(); ++i) + { + TEST_EQUAL(elementsXML[i], elementsO5M[i], ()); + } } diff --git a/generator/osm2type.cpp b/generator/osm2type.cpp index 6a2878834a..7a764460ca 100644 --- a/generator/osm2type.cpp +++ b/generator/osm2type.cpp @@ -68,7 +68,7 @@ namespace ftype TResult res = TResult(); for (auto & e : p->childs) { - if (e.tagKey == XMLElement::ET_TAG) + if (e.type == XMLElement::EntityType::Tag) { if (e.k.empty() || is_skip_tag(e.k)) continue; @@ -319,7 +319,7 @@ namespace ftype void ApplyRules(initializer_list<Rule<FuncT>> const & rules) const { for (auto & e : m_element->childs) - if (e.tagKey == XMLElement::ET_TAG) + if (e.type == XMLElement::EntityType::Tag) for (auto const & rule: rules) if (e.k == rule.key) { diff --git a/generator/osm_element.hpp b/generator/osm_element.hpp index a0e4f8cd48..fcbf7de3e9 100644 --- a/generator/osm_element.hpp +++ b/generator/osm_element.hpp @@ -23,7 +23,7 @@ /// @param TEmitter Feature accumulating policy /// @param THolder Nodes, ways, relations holder template <class TEmitter, class THolder> -class SecondPassParser : public BaseOSMParser +class SecondPassParser { TEmitter & m_emitter; THolder & m_holder; @@ -125,7 +125,7 @@ class SecondPassParser : public BaseOSMParser void GetNameKeys(NameKeysT & keys) const { for (auto const & p : m_current->childs) - if (p.tagKey == XMLElement::ET_TAG) + if (p.type == XMLElement::EntityType::Tag) { if (strings::StartsWith(p.k, "name")) keys.insert(p.k); @@ -145,7 +145,7 @@ class SecondPassParser : public BaseOSMParser return; } - bool const isWay = (m_current->tagKey == XMLElement::ET_WAY); + bool const isWay = (m_current->type == XMLElement::EntityType::Way); bool const isBoundary = isWay && (type == "boundary") && IsAcceptBoundary(e); NameKeysT nameKeys; @@ -201,7 +201,7 @@ class SecondPassParser : public BaseOSMParser // Get tags from parent relations. m_relationsProcess.Reset(p->id, p); - if (p->tagKey == XMLElement::ET_NODE) + if (p->type == XMLElement::EntityType::Node) { // additional process of nodes ONLY if there is no native types FeatureParams fp; @@ -209,7 +209,7 @@ class SecondPassParser : public BaseOSMParser if (!ftype::IsValidTypes(fp)) m_holder.ForEachRelationByNodeCached(p->id, m_relationsProcess); } - else if (p->tagKey == XMLElement::ET_WAY) + else if (p->type == XMLElement::EntityType::Way) { // always make additional process of ways m_holder.ForEachRelationByWayCached(p->id, m_relationsProcess); @@ -403,13 +403,13 @@ class SecondPassParser : public BaseOSMParser public: /// The main entry point for parsing process. - virtual void EmitElement(XMLElement * p) + void EmitElement(XMLElement * p) { FeatureParams params; if (!ParseType(p, params)) return; - if (p->tagKey == XMLElement::ET_NODE) + if (p->type == XMLElement::EntityType::Node) { m2::PointD pt; if (p->childs.empty() || !GetPoint(p->id, pt)) @@ -417,14 +417,14 @@ public: EmitPoint(pt, params, osm::Id::Node(p->id)); } - else if (p->tagKey == XMLElement::ET_WAY) + else if (p->type == XMLElement::EntityType::Way) { FeatureBuilderT ft; // Parse geometry. for (auto const & e : p->childs) { - if (e.tagKey == XMLElement::ET_ND) + if (e.type == XMLElement::EntityType::Nd) { m2::PointD pt; if (!GetPoint(e.ref, pt)) @@ -450,7 +450,7 @@ public: EmitLine(ft, params, isCoastLine); } - else if (p->tagKey == XMLElement::ET_RELATION) + else if (p->type == XMLElement::EntityType::Relation) { { // 1. Check, if this is our processable relation. Here we process only polygon relations. @@ -458,7 +458,7 @@ public: size_t const count = p->childs.size(); for (; i < count; ++i) { - if (p->childs[i].tagKey == XMLElement::ET_TAG && + if (p->childs[i].type == XMLElement::EntityType::Tag && p->childs[i].k == "type" && p->childs[i].v == "multipolygon") { @@ -475,7 +475,7 @@ public: // 3. Iterate ways to get 'outer' and 'inner' geometries for (auto const & e : p->childs) { - if (e.tagKey == XMLElement::ET_MEMBER && e.type == "way") + if (e.type == XMLElement::EntityType::Member && e.memberType == XMLElement::EntityType::Way) { if (e.role == "outer") outer.AddWay(e.ref); diff --git a/generator/osm_o5m_source.hpp b/generator/osm_o5m_source.hpp index 23700e9baf..be62eac092 100644 --- a/generator/osm_o5m_source.hpp +++ b/generator/osm_o5m_source.hpp @@ -242,11 +242,12 @@ public: struct Entity { + using EntityType = O5MSource::EntityType; EntityType type = EntityType::Reset; int64_t id = 0; uint64_t version = 0; - int32_t lon = 0; - int32_t lat = 0; + double lon = 0; + double lat = 0; int64_t timestamp = 0; int64_t changeset = 0; uint64_t uid = 0; @@ -454,10 +455,12 @@ public: } } +#define DECODE_O5M_COORD(coord) (static_cast<double>(coord) / 1E+7) + void ReadLonLat(Entity * const e) { - e->lon = (m_lon += ReadVarInt()); - e->lat = (m_lat += ReadVarInt()); + e->lon = DECODE_O5M_COORD(m_lon += ReadVarInt()); + e->lat = DECODE_O5M_COORD(m_lat += ReadVarInt()); } O5MSource * ReadEntity(Entity * const entity) diff --git a/generator/osm_source.cpp b/generator/osm_source.cpp index 5c9ff74260..482382d411 100644 --- a/generator/osm_source.cpp +++ b/generator/osm_source.cpp @@ -1,7 +1,6 @@ #include "generator/coastlines_generator.hpp" #include "generator/data_cache_file.hpp" #include "generator/feature_generator.hpp" -#include "generator/first_pass_parser.hpp" #include "generator/osm_decl.hpp" #include "generator/osm_element.hpp" #include "generator/osm_o5m_source.hpp" @@ -20,8 +19,6 @@ #include "defines.hpp" -#define DECODE_O5M_COORD(coord) (static_cast<double>(coord) / 1E+7) - SourceReader::SourceReader() : m_file(unique_ptr<istream,Deleter>(&cin, Deleter(false))) { @@ -343,70 +340,96 @@ public: }; } // anonymous namespace -template <typename HolderT> -void BuildIntermediateDataFromO5M(SourceReader & stream, HolderT & holder) -{ - using TType = osm::O5MSource::EntityType; - osm::O5MSource dataset([&stream](uint8_t * buffer, size_t size) - { - return stream.Read(reinterpret_cast<char *>(buffer), size); - }); - - for (auto const & em : dataset) +template <typename TElement, typename TCache> +void AddElementToCache(TCache & cache, TElement const & em) +{ + switch (em.type) { - switch (em.type) + case TElement::EntityType::Node: { - case TType::Node: + // Could do something with em.id, em.lon, em.lat here + // lon and lat are ints in 1E+7 * degree units + // convert to mercator + auto const pt = MercatorBounds::FromLatLon(em.lat, em.lon); + cache.AddNode(em.id, pt.y, pt.x); + break; + } + case TElement::EntityType::Way: + { + // store way + WayElement way(em.id); + for (uint64_t nd : em.Nodes()) + way.nodes.push_back(nd); + + if (way.IsValid()) + cache.AddWay(em.id, way); + break; + } + case TElement::EntityType::Relation: + { + // store relation + RelationElement relation; + for (auto const & member : em.Members()) { - // Could do something with em.id, em.lon, em.lat here - // lon and lat are ints in 1E+7 * degree units - // convert to mercator - auto const pt = MercatorBounds::FromLatLon(DECODE_O5M_COORD(em.lat), DECODE_O5M_COORD(em.lon)); - holder.AddNode(em.id, pt.y, pt.x); - break; + // Could do something with member ref (way or node or rel id depends on type), type and + // role + if (member.type == TElement::EntityType::Node) + relation.nodes.emplace_back(make_pair(member.ref, string(member.role))); + else if (member.type == TElement::EntityType::Way) + relation.ways.emplace_back(make_pair(member.ref, string(member.role))); + // we just ignore type == "relation" } - case TType::Way: - { - // store way - WayElement way(em.id); - for (uint64_t nd : em.Nodes()) - way.nodes.push_back(nd); - if (way.IsValid()) - holder.AddWay(em.id, way); - break; - } - case TType::Relation: - { - // store relation - RelationElement relation; - for (auto const & member : em.Members()) - { - // Could do something with member ref (way or node or rel id depends on type), type and - // role - if (member.type == TType::Node) - relation.nodes.emplace_back(make_pair(member.ref, string(member.role))); - else if (member.type == TType::Way) - relation.ways.emplace_back(make_pair(member.ref, string(member.role))); - // we just ignore type == "relation" - } - - for (auto const & tag : em.Tags()) - relation.tags.emplace(make_pair(string(tag.key), string(tag.value))); + for (auto const & tag : em.Tags()) + relation.tags.emplace(make_pair(string(tag.key), string(tag.value))); - if (relation.IsValid()) - holder.AddRelation(em.id, relation); + if (relation.IsValid()) + cache.AddRelation(em.id, relation); - break; - } - default: - break; + break; } + default: + break; } } -void BuildFeaturesFromO5M(SourceReader & stream, BaseOSMParser & parser) +template <typename TCache> +void BuildIntermediateDataFromXML(SourceReader & stream, TCache & cache) +{ + BaseOSMParser parser([&](XMLElement * e) + { + AddElementToCache(cache, *e); + }); + + ParseXMLSequence(stream, parser); +} + +void BuildFeaturesFromXML(SourceReader & stream, function<void(XMLElement *)> processor) +{ + BaseOSMParser parser([&](XMLElement * e) + { + processor(e); + }); + + ParseXMLSequence(stream, parser); +} + +template <typename TCache> +void BuildIntermediateDataFromO5M(SourceReader & stream, TCache & cache) +{ + using TType = osm::O5MSource::EntityType; + + osm::O5MSource dataset([&stream](uint8_t * buffer, size_t size) + { + return stream.Read(reinterpret_cast<char *>(buffer), size); + }); + + for (auto const & e : dataset) + AddElementToCache(cache, e); +} + +void BuildFeaturesFromO5M(SourceReader & stream, function<void(XMLElement *)> processor) { using TType = osm::O5MSource::EntityType; @@ -424,33 +447,33 @@ void BuildFeaturesFromO5M(SourceReader & stream, BaseOSMParser & parser) { case TType::Node: { - p.tagKey = XMLElement::ET_NODE; - p.lat = DECODE_O5M_COORD(em.lat); - p.lon = DECODE_O5M_COORD(em.lon); + p.type = XMLElement::EntityType::Node; + p.lat = em.lat; + p.lon = em.lon; break; } case TType::Way: { - p.tagKey = XMLElement::ET_WAY; + p.type = XMLElement::EntityType::Way; for (uint64_t nd : em.Nodes()) p.AddND(nd); break; } case TType::Relation: { - p.tagKey = XMLElement::ET_RELATION; + p.type = XMLElement::EntityType::Relation; for (auto const & member : em.Members()) { switch (member.type) { case TType::Node: - p.AddMEMBER(member.ref, "node", member.role); + p.AddMEMBER(member.ref, XMLElement::EntityType::Node, member.role); break; case TType::Way: - p.AddMEMBER(member.ref, "way", member.role); + p.AddMEMBER(member.ref, XMLElement::EntityType::Way, member.role); break; case TType::Relation: - p.AddMEMBER(member.ref, "relation", member.role); + p.AddMEMBER(member.ref, XMLElement::EntityType::Relation, member.role); break; default: break; @@ -464,7 +487,7 @@ void BuildFeaturesFromO5M(SourceReader & stream, BaseOSMParser & parser) for (auto const & tag : em.Tags()) p.AddKV(tag.key, tag.value); - parser.EmitElement(&p); + processor(&p); } } @@ -488,14 +511,16 @@ bool GenerateFeaturesImpl(feature::GenerateInfo & info) bucketer, cache, info.m_makeCoasts ? classif().GetCoastType() : 0, info.GetAddressesFileName()); + auto fn = [&parser](XMLElement * e) { parser.EmitElement(e); }; + SourceReader reader = info.m_osmFileName.empty() ? SourceReader() : SourceReader(info.m_osmFileName); switch (info.m_osmFileType) { case feature::GenerateInfo::OsmSourceType::XML: - ParseXMLSequence(reader, parser); + BuildFeaturesFromXML(reader, fn); break; case feature::GenerateInfo::OsmSourceType::O5M: - BuildFeaturesFromO5M(reader, parser); + BuildFeaturesFromO5M(reader, fn); break; } @@ -533,11 +558,8 @@ bool GenerateIntermediateDataImpl(feature::GenerateInfo & info) switch (info.m_osmFileType) { case feature::GenerateInfo::OsmSourceType::XML: - { - FirstPassParser<TDataCache> parser(cache); - ParseXMLSequence(reader, parser); + BuildIntermediateDataFromXML(reader, cache); break; - } case feature::GenerateInfo::OsmSourceType::O5M: BuildIntermediateDataFromO5M(reader, cache); break; diff --git a/generator/osm_source.hpp b/generator/osm_source.hpp index 246534153f..9db9f85cdd 100644 --- a/generator/osm_source.hpp +++ b/generator/osm_source.hpp @@ -1,9 +1,11 @@ #pragma once #include "generator/generate_info.hpp" +#include "generator/xml_element.hpp" #include "std/iostream.hpp" #include "std/unique_ptr.hpp" +#include "std/function.hpp" class SourceReader { @@ -33,7 +35,6 @@ public: bool GenerateFeatures(feature::GenerateInfo & info); bool GenerateIntermediateData(feature::GenerateInfo & info); -class BaseOSMParser; - -void BuildFeaturesFromO5M(SourceReader & stream, BaseOSMParser & parser); +void BuildFeaturesFromO5M(SourceReader & stream, function<void(XMLElement *)> processor); +void BuildFeaturesFromXML(SourceReader & stream, function<void(XMLElement *)> processor); diff --git a/generator/xml_element.cpp b/generator/xml_element.cpp index 07972865c0..5c03965117 100644 --- a/generator/xml_element.cpp +++ b/generator/xml_element.cpp @@ -1,7 +1,6 @@ #include "generator/xml_element.hpp" #include "coding/parse_xml.hpp" -#include "base/string_utils.hpp" #include "std/cstdio.hpp" #include "std/algorithm.hpp" @@ -12,7 +11,7 @@ void XMLElement::AddKV(string const & k, string const & v) childs.push_back(XMLElement()); XMLElement & e = childs.back(); - e.tagKey = ET_TAG; + e.type = EntityType::Tag; e.k = k; e.v = v; } @@ -22,44 +21,67 @@ void XMLElement::AddND(uint64_t ref) childs.push_back(XMLElement()); XMLElement & e = childs.back(); - e.tagKey = ET_ND; + e.type = EntityType::Nd; e.ref = ref; } -void XMLElement::AddMEMBER(uint64_t ref, string const & type, string const & role) +void XMLElement::AddMEMBER(uint64_t ref, EntityType type, string const & role) { childs.push_back(XMLElement()); XMLElement & e = childs.back(); - e.tagKey = ET_MEMBER; + e.type = EntityType::Member; e.ref = ref; - e.type = type; + e.memberType = type; e.role = role; } +string DebugPrint(XMLElement::EntityType e) +{ + switch (e) + { + case XMLElement::EntityType::Unknown: + return "Unknown"; + case XMLElement::EntityType::Way: + return "Way"; + case XMLElement::EntityType::Tag: + return "Tag"; + case XMLElement::EntityType::Relation: + return "Relation"; + case XMLElement::EntityType::Osm: + return "Osm"; + case XMLElement::EntityType::Node: + return "Node"; + case XMLElement::EntityType::Nd: + return "Nd"; + case XMLElement::EntityType::Member: + return "Member"; + } +} + string XMLElement::ToString(string const & shift) const { stringstream ss; ss << (shift.empty() ? "\n" : shift); - switch (tagKey) + switch (type) { - case ET_NODE: - ss << "Node: " << id << " (" << fixed << setw(7) << lat << ", " << lon << ")"; + case EntityType::Node: + ss << "Node: " << id << " (" << fixed << setw(7) << lat << ", " << lon << ")" << " subelements: " << childs.size(); break; - case ET_ND: + case EntityType::Nd: ss << "Nd ref: " << ref; break; - case ET_WAY: - ss << "Way: " << id << " elements: " << childs.size(); + case EntityType::Way: + ss << "Way: " << id << " subelements: " << childs.size(); break; - case ET_RELATION: - ss << "Relation: " << id << " elements: " << childs.size(); + case EntityType::Relation: + ss << "Relation: " << id << " subelements: " << childs.size(); break; - case ET_TAG: + case EntityType::Tag: ss << "Tag: " << k << " = " << v; break; - case ET_MEMBER: - ss << "Member: " << ref << " type: " << type << " role: " << role; + case EntityType::Member: + ss << "Member: " << ref << " type: " << DebugPrint(memberType) << " role: " << role; break; default: ss << "Unknown element"; @@ -79,90 +101,3 @@ string DebugPrint(XMLElement const & e) { return e.ToString(); } - - -void BaseOSMParser::AddAttr(string const & key, string const & value) -{ - if (!m_current) - return; - - if (key == "id") - CHECK ( strings::to_uint64(value, m_current->id), ("Unknown element with invalid id : ", value) ); - else if (key == "lon") - CHECK ( strings::to_double(value, m_current->lon), ("Bad node lon : ", value) ); - else if (key == "lat") - CHECK ( strings::to_double(value, m_current->lat), ("Bad node lat : ", value) ); - else if (key == "ref") - CHECK ( strings::to_uint64(value, m_current->ref), ("Bad node ref in way : ", value) ); - else if (key == "k") - m_current->k = value; - else if (key == "v") - m_current->v = value; - else if (key == "type") - m_current->type = value; - else if (key == "role") - m_current->role = value; -} - -bool BaseOSMParser::Push(string const & tagName) -{ - ASSERT_GREATER_OR_EQUAL(tagName.size(), 2, ()); - - // As tagKey we use first two char of tag name. - XMLElement::ETag tagKey = XMLElement::ETag(*reinterpret_cast<uint16_t const *>(tagName.data())); - - switch (tagKey) - { - // This tags will ignored in Push function. - case XMLElement::ET_MEMBER: - case XMLElement::ET_TAG: - case XMLElement::ET_ND: - return false; - default: break; - } - - switch (++m_depth) - { - case 1: - m_current = nullptr; - break; - case 2: - m_current = &m_parent; - m_current->tagKey = tagKey; - break; - default: - m_current = &m_child; - m_current->tagKey = tagKey; - } - return true; -} - -void BaseOSMParser::Pop(string const &) -{ - switch (--m_depth) - { - case 0: - break; - - case 1: - EmitElement(m_current); - m_parent.Clear(); - break; - - default: - switch (m_child.tagKey) - { - case XMLElement::ET_MEMBER: - m_parent.AddMEMBER(m_child.ref, m_child.type, m_child.role); - break; - case XMLElement::ET_TAG: - m_parent.AddKV(m_child.k, m_child.v); - break; - case XMLElement::ET_ND: - m_parent.AddND(m_child.ref); - default: break; - } - m_current = &m_parent; - m_child.Clear(); - } -} diff --git a/generator/xml_element.hpp b/generator/xml_element.hpp index 42fb3b0540..3dd38745c2 100644 --- a/generator/xml_element.hpp +++ b/generator/xml_element.hpp @@ -1,52 +1,53 @@ #pragma once #include "base/math.hpp" - +#include "base/string_utils.hpp" #include "std/string.hpp" #include "std/vector.hpp" #include "std/map.hpp" #include "std/iostream.hpp" +#include "std/function.hpp" #include "std/exception.hpp" #include "std/iomanip.hpp" struct XMLElement { - enum ETag + enum class EntityType { - ET_UNKNOWN = 0, - ET_OSM = 0x736F, // "os" - ET_NODE = 0x6F6E, // "no" - ET_WAY = 0x6177, // "wa" - ET_RELATION = 0x6572, // "re" - ET_TAG = 0x6174, // "ta" - ET_ND = 0x646E, // "nd" - ET_MEMBER = 0x656D // "me" + Unknown = 0x0, + Node = 0x6F6E, // "no" + Way = 0x6177, // "wa" + Relation = 0x6572, // "re" + Tag = 0x6174, // "ta" + Nd = 0x646E, // "nd" + Member = 0x656D, // "me" + Osm = 0x736F, // "os" }; - ETag tagKey = ET_UNKNOWN; + EntityType type = EntityType::Unknown; uint64_t id = 0; double lon = 0; double lat = 0; uint64_t ref = 0; string k; string v; - string type; + EntityType memberType = EntityType::Unknown; string role; vector<XMLElement> childs; void Clear() { - tagKey = ET_UNKNOWN; + type = EntityType::Unknown; id = 0; lon = 0; lat = 0; ref = 0; k.clear(); v.clear(); - type.clear(); + memberType = EntityType::Unknown; role.clear(); childs.clear(); @@ -54,25 +55,83 @@ struct XMLElement string ToString(string const & shift = string()) const; + vector<uint64_t> Nodes() const + { + vector<uint64_t> nds; + for (auto const & e : childs) + { + if (e.type == EntityType::Nd) + nds.push_back(e.ref); + } + return move(nds); + } + + struct Member + { + uint64_t ref; + EntityType type; + string role; + }; + + static EntityType StringToEntityType(string const & t) + { + if (t == "way") + return EntityType::Way; + if (t == "node") + return EntityType::Node; + if (t == "relation") + return EntityType::Relation; + ASSERT(false, ("Unknown type", t)); + return EntityType::Unknown; + } + + vector<Member> Members() const + { + vector<Member> members; + for (auto const & e : childs) + { + if (e.type == EntityType::Member) + members.push_back({e.ref, e.memberType, e.role}); + } + return move(members); + } + + struct Tag + { + string key; + string value; + }; + + vector<Tag> Tags() const + { + vector<Tag> tags; + for (auto const & e : childs) + { + if (e.type == EntityType::Tag) + tags.push_back({e.k, e.v}); + } + return move(tags); + } + bool operator == (XMLElement const & e) const { return ( - tagKey == e.tagKey + type == e.type && id == e.id && my::AlmostEqualAbs(lon, e.lon, 1e-7) && my::AlmostEqualAbs(lat, e.lat, 1e-7) && ref == e.ref && k == e.k && v == e.v - && type == e.type + && memberType == e.memberType && role == e.role - && childs == childs + && childs == e.childs ); } void AddKV(string const & k, string const & v); void AddND(uint64_t ref); - void AddMEMBER(uint64_t ref, string const & type, string const & role); + void AddMEMBER(uint64_t ref, EntityType type, string const & role); }; string DebugPrint(XMLElement const & e); @@ -82,18 +141,90 @@ class BaseOSMParser XMLElement m_parent; XMLElement m_child; - size_t m_depth; + size_t m_depth = 0; + XMLElement * m_current = nullptr; -protected: - XMLElement * m_current; + using TEmmiterFn = function<void(XMLElement *)>; + TEmmiterFn m_EmmiterFn; public: - BaseOSMParser() : m_depth(0), m_current(0) {} + BaseOSMParser(TEmmiterFn fn) : m_EmmiterFn(fn) {} - void AddAttr(string const & key, string const & value); - bool Push(string const & tagName); - void Pop(string const &); void CharData(string const &) {} - virtual void EmitElement(XMLElement * p) = 0; + void AddAttr(string const & key, string const & value) + { + if (!m_current) + return; + + if (key == "id") + CHECK ( strings::to_uint64(value, m_current->id), ("Unknown element with invalid id : ", value) ); + else if (key == "lon") + CHECK ( strings::to_double(value, m_current->lon), ("Bad node lon : ", value) ); + else if (key == "lat") + CHECK ( strings::to_double(value, m_current->lat), ("Bad node lat : ", value) ); + else if (key == "ref") + CHECK ( strings::to_uint64(value, m_current->ref), ("Bad node ref in way : ", value) ); + else if (key == "k") + m_current->k = value; + else if (key == "v") + m_current->v = value; + else if (key == "type") + m_current->memberType = XMLElement::StringToEntityType(value); + else if (key == "role") + m_current->role = value; + } + + bool Push(string const & tagName) + { + ASSERT_GREATER_OR_EQUAL(tagName.size(), 2, ()); + + // As tagKey we use first two char of tag name. + XMLElement::EntityType tagKey = XMLElement::EntityType(*reinterpret_cast<uint16_t const *>(tagName.data())); + + switch (++m_depth) + { + case 1: + m_current = nullptr; + break; + case 2: + m_current = &m_parent; + m_current->type = tagKey; + break; + default: + m_current = &m_child; + m_current->type = tagKey; + } + return true; + } + + void Pop(string const & v) + { + switch (--m_depth) + { + case 0: + break; + + case 1: + m_EmmiterFn(m_current); + m_parent.Clear(); + break; + + default: + switch (m_child.type) + { + case XMLElement::EntityType::Member: + m_parent.AddMEMBER(m_child.ref, m_child.memberType, m_child.role); + break; + case XMLElement::EntityType::Tag: + m_parent.AddKV(m_child.k, m_child.v); + break; + case XMLElement::EntityType::Nd: + m_parent.AddND(m_child.ref); + default: break; + } + m_current = &m_parent; + m_child.Clear(); + } + } }; |