From 5f515c98c2a7c92a4257de1de97890615c2bbd88 Mon Sep 17 00:00:00 2001 From: Sergey Yershov Date: Wed, 14 Jan 2015 20:59:22 +0300 Subject: [PATCH] Change XMLElement name as string to tagKey as enum Unified work with XML tags in both stage parsers Change storage method for XML attributes --- generator/first_pass_parser.hpp | 66 +++++++++----------------- generator/osm2type.cpp | 12 ++--- generator/osm_element.hpp | 84 +++++++++++++++------------------ generator/xml_element.cpp | 76 ++++++++++++++++++++--------- generator/xml_element.hpp | 32 ++++++++----- indexer/classificator.hpp | 6 +-- 6 files changed, 143 insertions(+), 133 deletions(-) diff --git a/generator/first_pass_parser.hpp b/generator/first_pass_parser.hpp index b0f79a6ab9..886e505a47 100644 --- a/generator/first_pass_parser.hpp +++ b/generator/first_pass_parser.hpp @@ -16,77 +16,57 @@ class FirstPassParser : public BaseOSMParser public: FirstPassParser(THolder & holder) : m_holder(holder) { - static char const * tags[] = { "osm", "node", "way", "relation" }; - SetTags(tags); } protected: virtual void EmitElement(XMLElement * p) { - uint64_t id; - VERIFY ( strings::to_uint64(p->attrs["id"], id), ("Unknown element with invalid id : ", p->attrs["id"]) ); - - if (p->name == "node") + if (p->tagKey == XMLElement::ET_NODE) { // store point - double lat, lng; - VERIFY ( strings::to_double(p->attrs["lat"], lat), ("Bad node lat : ", p->attrs["lat"]) ); - VERIFY ( strings::to_double(p->attrs["lon"], lng), ("Bad node lon : ", p->attrs["lon"]) ); - // convert to mercator - lat = MercatorBounds::LatToY(lat); - lng = MercatorBounds::LonToX(lng); + p->lat = MercatorBounds::LatToY(p->lat); + p->lng = MercatorBounds::LonToX(p->lng); - m_holder.AddNode(id, lat, lng); + m_holder.AddNode(p->id, p->lat, p->lng); } - else if (p->name == "way") + else if (p->tagKey == XMLElement::ET_WAY) { // store way - WayElement e(id); + WayElement way(p->id); - for (size_t i = 0; i < p->childs.size(); ++i) - { - if (p->childs[i].name == "nd") - { - uint64_t ref; - VERIFY ( strings::to_uint64(p->childs[i].attrs["ref"], ref), ("Bad node ref in way : ", p->childs[i].attrs["ref"]) ); - e.nodes.push_back(ref); - } - } + for (auto const & e: p->childs) + if (e.tagKey == XMLElement::ET_ND) + way.nodes.push_back(e.ref); - if (e.IsValid()) - m_holder.AddWay(id, e); + if (way.IsValid()) + m_holder.AddWay(p->id, way); } - else if (p->name == "relation") + else if (p->tagKey == XMLElement::ET_RELATION) { // store relation - RelationElement e; - for (size_t i = 0; i < p->childs.size(); ++i) + RelationElement relation; + for (auto const & e: p->childs) { - if (p->childs[i].name == "member") + if (e.tagKey == XMLElement::ET_MEMBER) { - uint64_t ref; - VERIFY ( strings::to_uint64(p->childs[i].attrs["ref"], ref), ("Bad ref in relation : ", p->childs[i].attrs["ref"]) ); - - string const & type = p->childs[i].attrs["type"]; - string const & role = p->childs[i].attrs["role"]; - if (type == "node") - e.nodes.push_back(make_pair(ref, role)); - else if (type == "way") - e.ways.push_back(make_pair(ref, role)); + 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 (p->childs[i].name == "tag") + else if (e.tagKey == XMLElement::ET_TAG) { // relation tags writing as is - e.tags.insert(make_pair(p->childs[i].attrs["k"], p->childs[i].attrs["v"])); + relation.tags.insert(make_pair(e.k, e.v)); } } - if (e.IsValid()) - m_holder.AddRelation(id, e); + if (relation.IsValid()) + m_holder.AddRelation(p->id, relation); } } }; diff --git a/generator/osm2type.cpp b/generator/osm2type.cpp index d00f718ed9..e31ef9a358 100644 --- a/generator/osm2type.cpp +++ b/generator/osm2type.cpp @@ -69,14 +69,14 @@ namespace ftype res_t res = res_t(); for (size_t i = 0; i < p->childs.size(); ++i) { - if (p->childs[i].name == "tag") + if (p->childs[i].tagKey == XMLElement::ET_TAG) { - string & k = p->childs[i].attrs["k"]; + string & k = p->childs[i].k; if (k.empty() || is_skip_tag(k)) continue; - string & v = p->childs[i].attrs["v"]; + string & v = p->childs[i].v; // this means "no" if (get_mark_value(k, v) == -1) @@ -374,7 +374,7 @@ namespace ftype for_each_tag(p, bind(ref(setLayer), _1, _2)); if (!isLayer && layer) - p->AddKV("layer", layer); + p->AddKV("layer", layer); } //#ifdef DEBUG @@ -402,10 +402,10 @@ namespace ftype { Classificator const & c = classif(); - for (auto &e: (Classificator::Path1T[]){ {"entrance"}, {"highway"} }) + for (auto const & e : (Classificator::Path1T[]){ {"entrance"}, {"highway"} }) m_types.push_back(c.GetTypeByPath( {e[0]} )); - for (auto &e: (Classificator::Path2T[]){ {"building", "address"}, {"hwtag", "oneway"}, {"hwtag", "private"}, {"hwtag", "lit"} }) + for (auto const & e : (Classificator::Path2T[]){ {"building", "address"}, {"hwtag", "oneway"}, {"hwtag", "private"}, {"hwtag", "lit"} }) m_types.push_back(c.GetTypeByPath( {e[0], e[1]} )); } diff --git a/generator/osm_element.hpp b/generator/osm_element.hpp index fd5ec1a729..37ac33cc05 100644 --- a/generator/osm_element.hpp +++ b/generator/osm_element.hpp @@ -125,10 +125,16 @@ class SecondPassParser : public BaseOSMParser { for (auto const & p : m_current->childs) { - if (p.name == "tag") - for (auto const & a : p.attrs) - if (strings::StartsWith(a.first, "name")) + if (p.tagKey == XMLElement::ET_TAG) + { + if (strings::StartsWith(p.k, "name")) return true; + if (strings::StartsWith(p.v, "name")) + return true; + } +// for (auto const & a : p.attrs) +// if (strings::StartsWith(a.first, "name")) +// return true; } return false; @@ -147,7 +153,7 @@ class SecondPassParser : public BaseOSMParser return; } - bool const isWay = (m_current->name == "way"); + bool const isWay = (m_current->tagKey == XMLElement::ET_WAY); bool const isBoundary = isWay && (type == "boundary") && IsAcceptBoundary(e); bool const hasName = HasName(); @@ -195,25 +201,23 @@ class SecondPassParser : public BaseOSMParser } m_relationsProcess; - bool ParseType(XMLElement * p, uint64_t & id, FeatureParams & params) + bool ParseType(XMLElement * p, FeatureParams & params) { - CHECK(strings::to_uint64(p->attrs["id"], id), (p->attrs["id"])); - // Get tags from parent relations. - m_relationsProcess.Reset(id, p); + m_relationsProcess.Reset(p->id, p); - if (p->name == "node") + if (p->tagKey == XMLElement::ET_NODE) { // additional process of nodes ONLY if there is no native types FeatureParams fp; ftype::GetNameAndType(p, fp); if (!ftype::IsValidTypes(fp)) - m_holder.ForEachRelationByNodeCached(id, m_relationsProcess); + m_holder.ForEachRelationByNodeCached(p->id, m_relationsProcess); } - else if (p->name == "way") + else if (p->tagKey == XMLElement::ET_WAY) { // always make additional process of ways - m_holder.ForEachRelationByWayCached(id, m_relationsProcess); + m_holder.ForEachRelationByWayCached(p->id, m_relationsProcess); } // Get params from element tags. @@ -386,33 +390,29 @@ class SecondPassParser : public BaseOSMParser /// The main entry point for parsing process. virtual void EmitElement(XMLElement * p) { - uint64_t id; FeatureParams params; - if (!ParseType(p, id, params)) + if (!ParseType(p, params)) return; - if (p->name == "node") + if (p->tagKey == XMLElement::ET_NODE) { m2::PointD pt; - if (p->childs.empty() || !GetPoint(id, pt)) + if (p->childs.empty() || !GetPoint(p->id, pt)) return; - EmitPoint(pt, params, osm::Id::Node(id)); + EmitPoint(pt, params, osm::Id::Node(p->id)); } - else if (p->name == "way") + else if (p->tagKey == XMLElement::ET_WAY) { FeatureBuilderT ft; // Parse geometry. - for (size_t i = 0; i < p->childs.size(); ++i) + for (auto const & e : p->childs) { - if (p->childs[i].name == "nd") + if (e.tagKey == XMLElement::ET_ND) { - uint64_t nodeID; - CHECK ( strings::to_uint64(p->childs[i].attrs["ref"], nodeID), (p->childs[i].attrs["ref"]) ); - m2::PointD pt; - if (!GetPoint(nodeID, pt)) + if (!GetPoint(e.ref, pt)) return; ft.AddPoint(pt); @@ -422,20 +422,20 @@ class SecondPassParser : public BaseOSMParser if (ft.GetPointsCount() < 2) return; - ft.SetOsmId(osm::Id::Way(id)); + ft.SetOsmId(osm::Id::Way(p->id)); bool isCoastLine = (m_coastType != 0 && params.IsTypeExist(m_coastType)); EmitArea(ft, params, [&] (FeatureBuilderT & ft) { isCoastLine = false; // emit coastline feature only once - multipolygon_holes_processor processor(id, this); - m_holder.ForEachRelationByWay(id, processor); + multipolygon_holes_processor processor(p->id, this); + m_holder.ForEachRelationByWay(p->id, processor); ft.SetAreaAddHoles(processor.GetHoles()); }); EmitLine(ft, params, isCoastLine); } - else if (p->name == "relation") + else if (p->tagKey == XMLElement::ET_RELATION) { { // 1. Check, if this is our processable relation. Here we process only polygon relations. @@ -443,9 +443,9 @@ class SecondPassParser : public BaseOSMParser size_t const count = p->childs.size(); for (; i < count; ++i) { - if (p->childs[i].name == "tag" && - p->childs[i].attrs["k"] == "type" && - p->childs[i].attrs["v"] == "multipolygon") + if (p->childs[i].tagKey == XMLElement::ET_TAG && + p->childs[i].k == "type" && + p->childs[i].v == "multipolygon") { break; } @@ -458,23 +458,18 @@ class SecondPassParser : public BaseOSMParser AreaWayMerger outer(m_holder); // 3. Iterate ways to get 'outer' and 'inner' geometries - for (size_t i = 0; i < p->childs.size(); ++i) + for (auto const & e : p->childs) { - if (p->childs[i].name == "member" && - p->childs[i].attrs["type"] == "way") + if (e.tagKey == XMLElement::ET_MEMBER && e.type == "way") { - string const & role = p->childs[i].attrs["role"]; - uint64_t wayID; - CHECK ( strings::to_uint64(p->childs[i].attrs["ref"], wayID), (p->childs[i].attrs["ref"]) ); - - if (role == "outer") - outer.AddWay(wayID); - else if (role == "inner") - holes(wayID); + if (e.role == "outer") + outer.AddWay(e.ref); + else if (e.role == "inner") + holes(e.ref); } } - multipolygons_emitter emitter(this, params, holes.GetHoles(), id); + multipolygons_emitter emitter(this, params, holes.GetHoles(), p->id); outer.ForEachArea(emitter, true); } } @@ -484,9 +479,6 @@ public: uint32_t coastType, string const & addrFilePath) : m_emitter(emitter), m_holder(holder), m_coastType(coastType) { - char const * tags[] = { "osm", "node", "way", "relation" }; - SetTags(tags); - if (!addrFilePath.empty()) m_addrWriter.reset(new FileWriter(addrFilePath)); } diff --git a/generator/xml_element.cpp b/generator/xml_element.cpp index 72af0c9a21..52221e88c6 100644 --- a/generator/xml_element.cpp +++ b/generator/xml_element.cpp @@ -1,38 +1,74 @@ #include "xml_element.hpp" #include "../coding/parse_xml.hpp" +#include "../base/string_utils.hpp" #include "../std/cstdio.hpp" #include "../std/algorithm.hpp" -void XMLElement::Clear() -{ - name.clear(); - attrs.clear(); - childs.clear(); - parent = 0; -} - void XMLElement::AddKV(string const & k, string const & v) { childs.push_back(XMLElement()); XMLElement & e = childs.back(); - e.name = "tag"; - e.attrs["k"] = k; - e.attrs["v"] = v; + e.tagKey = ET_TAG; + e.k = k; + e.v = v; e.parent = this; } -bool BaseOSMParser::is_our_tag(string const & name) +void BaseOSMParser::AddAttr(string const & key, string const & value) { - return (find(m_tags.begin(), m_tags.end(), name) != m_tags.end()); + if (m_current) + { + if (key == "id") + VERIFY ( strings::to_uint64(value, m_current->id), ("Unknown element with invalid id : ", value) ); + else if (key == "lon") + VERIFY ( strings::to_double(value, m_current->lng), ("Bad node lon : ", value) ); + else if (key == "lat") + VERIFY ( strings::to_double(value, m_current->lat), ("Bad node lon : ", value) ); + else if (key == "ref") + VERIFY ( 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 & name) +bool BaseOSMParser::MatchTag(string const & tagName, XMLElement::ETag &tagKey) { - if (!is_our_tag(name) && (m_depth != 2)) + static const TagT allowedTags[] = { + {"nd", XMLElement::ET_ND, false}, + {"node", XMLElement::ET_NODE, true}, + {"tag", XMLElement::ET_TAG, false}, + {"way", XMLElement::ET_WAY, true}, + {"relation", XMLElement::ET_RELATION, true}, + {"member", XMLElement::ET_MEMBER, false}, + {"osm", XMLElement::ET_OSM, true} + }; + + tagKey = XMLElement::ET_UNKNOWN; + for (auto const & e : allowedTags) { + if (tagName == e.tagName) + { + tagKey = e.tagKey; + return e.allowed; + } + } + return false; +} + +bool BaseOSMParser::Push(string const & tagName) +{ + XMLElement::ETag tagKey; + + if (!MatchTag(tagName, tagKey) && (m_depth != 2)) return false; ++m_depth; @@ -54,16 +90,10 @@ bool BaseOSMParser::Push(string const & name) } if (m_depth >= 2) - m_current->name = name; + m_current->tagKey = tagKey; return true; } -void BaseOSMParser::AddAttr(string const & name, string const & value) -{ - if (m_current) - m_current->attrs[name] = value; -} - void BaseOSMParser::Pop(string const &) { --m_depth; @@ -74,7 +104,7 @@ void BaseOSMParser::Pop(string const &) else if (m_depth == 1) { EmitElement(m_current); - m_current->Clear(); + (*m_current) = XMLElement(); } } diff --git a/generator/xml_element.hpp b/generator/xml_element.hpp index abbc4a9d9b..c201ff8e98 100644 --- a/generator/xml_element.hpp +++ b/generator/xml_element.hpp @@ -3,15 +3,23 @@ #include "../std/vector.hpp" #include "../std/map.hpp" +#include "../std/iostream.hpp" struct XMLElement { - string name; - map attrs; + enum ETag {ET_UNKNOWN = 0, ET_OSM = 1, ET_NODE = 2, ET_WAY = 3, ET_RELATION = 4, ET_TAG = 5, ET_ND = 6, ET_MEMBER = 7}; + ETag tagKey = ET_UNKNOWN; + uint64_t id = 0; + double lng = 0; + double lat = 0; + uint64_t ref = 0; + string k; + string v; + string type; + string role; + vector childs; - XMLElement * parent; - - void Clear(); + XMLElement * parent = nullptr; void AddKV(string const & k, string const & v); }; @@ -19,24 +27,24 @@ struct XMLElement class BaseOSMParser { XMLElement m_element; - XMLElement * m_current; size_t m_depth; - vector m_tags; - bool is_our_tag(string const & name); + typedef struct { char const * tagName; XMLElement::ETag tagKey; bool allowed;} TagT; + +protected: + XMLElement * m_current; public: BaseOSMParser() : m_current(0), m_depth(0) {} - template void SetTags(char const * (&arr)[N]) { m_tags.assign(&arr[0], &arr[N]); } - - bool Push(string const & name); - void AddAttr(string const & name, string const & value); + void AddAttr(string const & key, string const & value); + bool Push(string const & tagName); void Pop(string const &); void CharData(string const &) {} protected: + bool MatchTag(string const & tagName, XMLElement::ETag &tagKey); virtual void EmitElement(XMLElement * p) = 0; }; diff --git a/indexer/classificator.hpp b/indexer/classificator.hpp index 253754bf66..66d33c065f 100644 --- a/indexer/classificator.hpp +++ b/indexer/classificator.hpp @@ -169,9 +169,9 @@ class Classificator : private noncopyable public: - typedef const char * Path1T[1]; - typedef const char * Path2T[2]; - typedef const char * Path3T[3]; + typedef const char * const Path1T[1]; + typedef const char * const Path2T[2]; + typedef const char * const Path3T[3]; Classificator() : m_root("world") {}