Change XMLElement name as string to tagKey as enum

Unified work with XML tags in both stage parsers
Change storage method for XML attributes
This commit is contained in:
Sergey Yershov 2015-01-14 20:59:22 +03:00 committed by Alex Zolotarev
parent a44338d9a2
commit 5f515c98c2
6 changed files with 143 additions and 133 deletions

View file

@ -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);
}
}
};

View file

@ -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<bool>(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]} ));
}

View file

@ -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<THolder> 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));
}

View file

@ -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();
}
}

View file

@ -3,15 +3,23 @@
#include "../std/vector.hpp"
#include "../std/map.hpp"
#include "../std/iostream.hpp"
struct XMLElement
{
string name;
map<string, string> 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<XMLElement> 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<string> 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 <size_t N> 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;
};

View file

@ -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") {}