forked from organicmaps/organicmaps
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:
parent
a44338d9a2
commit
5f515c98c2
6 changed files with 143 additions and 133 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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]} ));
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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") {}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue