diff --git a/indexer/indexer_tests/xml_feature_test.cpp b/indexer/indexer_tests/xml_feature_test.cpp
index 66ffc68fb2..cbe81ef914 100644
--- a/indexer/indexer_tests/xml_feature_test.cpp
+++ b/indexer/indexer_tests/xml_feature_test.cpp
@@ -25,63 +25,63 @@
using namespace indexer;
-UNIT_TEST(FeatureToXml)
-{
- XMLFeature feature;
- feature.SetModificationTime(my::StringToTimestamp("2015-11-27T21:13:32Z"));
+// UNIT_TEST(FeatureToXml)
+// {
+// XMLFeature feature;
+// feature.SetModificationTime(my::StringToTimestamp("2015-11-27T21:13:32Z"));
- feature.SetCenter({64.234234, 53.31242});
- feature.SetTagValue("opening_hours", "Mo-Fr 08:15-17:30");
+// feature.SetCenter({64.234234, 53.31242});
+// feature.SetTagValue("opening_hours", "Mo-Fr 08:15-17:30");
- feature.SetInterationalName("Gorki Park");
+// feature.SetInterationalName("Gorki Park");
- StringUtf8Multilang names;
- names.AddString("en", "Gorki Park");
- names.AddString("ru", "Парк Горького");
+// StringUtf8Multilang names;
+// names.AddString("en", "Gorki Park");
+// names.AddString("ru", "Парк Горького");
- feature.SetMultilungName(names);
+// feature.SetMultilungName(names);
- StringNumericOptimal house;
- house.Set(10);
- feature.SetHouse(house);
+// StringNumericOptimal house;
+// house.Set(10);
+// feature.SetHouse(house);
- pugi::xml_document document;
- feature.ToXMLDocument(document);
+// pugi::xml_document document;
+// feature.ToXMLDocument(document);
- stringstream sstr;
- document.save(sstr, "\t", pugi::format_indent_attributes);
+// stringstream sstr;
+// document.save(sstr, "\t", pugi::format_indent_attributes);
- auto const expectedString = R"(
-
-
-
-
-
-
-
-)";
+// auto const expectedString = R"(
+//
+//
+//
+//
+//
+//
+//
+// )";
- TEST_EQUAL(sstr.str(), expectedString, ());
-}
+// TEST_EQUAL(sstr.str(), expectedString, ());
+// }
UNIT_TEST(FeatureFromXml)
{
auto const srcString = R"(
)";
- pugi::xml_document srcDocument;
- srcDocument.load_string(srcString);
- auto const feature = XMLFeature::FromXMLDocument(srcDocument);
+ XMLFeature feature(srcString);
- pugi::xml_document dstDocument;
- TEST(feature.ToXMLDocument(dstDocument), ());
stringstream sstr;
- dstDocument.save(sstr, "\t", pugi::format_indent_attributes);
+ feature.GetXMLDocument().save(sstr, "\t", pugi::format_indent_attributes);
+ TEST_EQUAL(srcString, sstr.str(), ());
- TEST_EQUAL(sstr.str(), srcString, ());
+ TEST(feature.HasTag("opening_hours"), ());
+ TEST(!feature.HasTag("FooBarBaz"), ());
+
+ TEST_EQUAL(feature.GetHouse(), "10", ());
+ TEST_EQUAL(feature.GetCenter(), m2::PointD(64.2342340, 53.3124200), ());
+
+ TEST_EQUAL(feature.GetName(), "Gorki Park", ());
+ TEST_EQUAL(feature.GetName("default"), "Gorki Park", ());
+ TEST_EQUAL(feature.GetName("en"), "Gorki Park", ());
+ TEST_EQUAL(feature.GetName("ru"), "Парк Горького", ());
+ TEST_EQUAL(feature.GetName("No such language"), "", ());
+
+ TEST_EQUAL(feature.GetTagValue("opening_hours"), "Mo-Fr 08:15-17:30", ());
+ TEST_EQUAL(my::TimestampToString(feature.GetModificationTime()), "2015-11-27T21:13:32Z", ());
}
diff --git a/indexer/xml_feature.cpp b/indexer/xml_feature.cpp
index f01ea6d598..54b23f56a0 100644
--- a/indexer/xml_feature.cpp
+++ b/indexer/xml_feature.cpp
@@ -5,13 +5,15 @@
#include "std/cstring.hpp"
+#include "3party/pugixml/src/pugixml.hpp"
+
namespace
{
string ToString(m2::PointD const & p)
{
ostringstream out;
- out.precision(20);
+ out.precision(7);
out << p.x << ", " << p.y;
return out.str();
}
@@ -34,17 +36,24 @@ void AddTag(string const & key, string const & value, pugi::xml_node & node)
tag.append_attribute("k") = key.data();
tag.append_attribute("v") = value.data();
}
+
+pugi::xpath_node FindTag(pugi::xml_document const & document, string const & key)
+{
+ return document.select_node(("//tag[@k='" + key + "']").data());
}
+} // namespace
-#include
namespace indexer
{
-XMLFeature XMLFeature::FromXMLDocument(pugi::xml_document const & document)
-{
- XMLFeature feature;
+XMLFeature::XMLFeature(): m_documentPtr(new pugi::xml_document) {}
- auto const & node = document.child("node");
+XMLFeature::XMLFeature(string const & xml):
+ XMLFeature()
+{
+ m_documentPtr->load(xml.data());
+
+ auto const node = m_documentPtr->child("node");
if (!node)
MYTHROW(XMLFeatureError, ("Document has no node"));
@@ -55,57 +64,78 @@ XMLFeature XMLFeature::FromXMLDocument(pugi::xml_document const & document)
m2::PointD center;
if (!FromString(attr.value(), center))
MYTHROW(XMLFeatureError, ("Can't parse center attribute: " + string(attr.value())));
- feature.SetCenter(center);
if (!(attr = node.attribute("timestamp")))
MYTHROW(XMLFeatureError, ("Node has no timestamp attribute"));
- feature.SetModificationTime(my::StringToTimestamp(attr.value()));
-
- for (auto const tag : node.children())
- {
- auto const tagName = tag.attribute("k").value();
- auto const tagValue = tag.attribute("v").value();
- if (strings::StartsWith(tagName, "name::"))
- {
- auto const lang = tagName + strlen("name::");
- feature.m_name.AddString(lang, tagValue);
- }
- else if (strcmp("name", tagName) == 0)
- {
- feature.SetInterationalName(tagValue);
- }
- else if (strcmp("addr::housenumber", tagName) == 0)
- {
- feature.m_house.Set(tagValue);
- }
- else
- {
- feature.m_tags[tagName] = tagValue;
- }
- }
-
- return feature;
}
-bool XMLFeature::ToXMLDocument(pugi::xml_document & document) const
+pugi::xml_document const & XMLFeature::GetXMLDocument() const
{
- auto node = document.append_child("node");
- node.append_attribute("center") = ToString(GetCenter()).data();
- node.append_attribute("timestamp") = my::TimestampToString(GetModificationTime()).data();
-
- AddTag("name", GetInternationalName(), node);
-
- GetMultilangName().ForEachRef([&node](int8_t lang, string const & name) {
- AddTag("name::" + string(StringUtf8Multilang::GetLangByCode(lang)), name, node);
- return true;
- });
-
- if (!GetHouse().Get().empty())
- AddTag("addr:housenumber", GetHouse().Get(), node);
-
- for (auto const & tag : m_tags)
- AddTag(tag.first, tag.second, node);
-
- return true;
+ return *m_documentPtr;
}
+
+m2::PointD XMLFeature::GetCenter() const
+{
+ auto const node = m_documentPtr->child("node");
+ m2::PointD center;
+ FromString(node.attribute("center").value(), center);
+ return center;
+}
+
+string const XMLFeature::GetName(string const & lang) const
+{
+ auto const suffix = lang == "default" || lang.empty() ? "" : "::" + lang;
+ return GetTagValue("name" + suffix);
+}
+
+string const XMLFeature::GetName(uint8_t const langCode) const
+{
+ return GetName(StringUtf8Multilang::GetLangByCode(langCode));
+}
+
+string const XMLFeature::GetHouse() const
+{
+ return GetTagValue("addr:housenumber");
+}
+
+time_t XMLFeature::GetModificationTime() const
+{
+ auto const node = m_documentPtr->child("node");
+ return my::StringToTimestamp(node.attribute("timestamp").value());
+}
+
+bool XMLFeature::HasTag(string const & key) const
+{
+ return FindTag(*m_documentPtr, key);
+}
+
+string XMLFeature::GetTagValue(string const & key) const
+{
+ auto const tag = FindTag(*m_documentPtr, key);
+ return tag.node().attribute("v").value();
+}
+
+// bool XMLFeature::ToXMLDocument(pugi::xml_document & document) const
+// {
+// auto node = document.append_child("node");
+// node.append_attribute("center") = ToString(GetCenter()).data();
+// node.append_attribute("timestamp") = my::TimestampToString(GetModificationTime()).data();
+
+// AddTag("name", GetInternationalName(), node);
+
+// GetMultilangName().ForEachRef([&node](int8_t lang, string const & name) {
+// AddTag("name::" + string(StringUtf8Multilang::GetLangByCode(lang)), name, node);
+// return true;
+// });
+
+// if (!GetHouse().Get().empty())
+// AddTag("addr:housenumber", GetHouse().Get(), node);
+
+// for (auto const & tag : m_tags)
+// AddTag(tag.first, tag.second, node);
+
+// return true;
+// }
+
+
} // namespace indexer
diff --git a/indexer/xml_feature.hpp b/indexer/xml_feature.hpp
index f6e0425960..08bfe448db 100644
--- a/indexer/xml_feature.hpp
+++ b/indexer/xml_feature.hpp
@@ -7,77 +7,41 @@
#include "std/ctime.hpp"
#include "std/map.hpp"
+#include "std/unique_ptr.hpp"
-#include "3party/pugixml/src/pugixml.hpp"
+
+namespace pugi
+{
+class xml_document;
+}
namespace indexer
{
-class FeatureTags
-{
-public:
- bool HasKey(string const & key) const { return m_data.find(key) == end(m_data); }
-
- string GetValue(string const & key) const { return HasKey(key) ? m_data.find(key)->second : ""; }
-
- void SetValue(string const key, string const & value) { m_data[key] = value; }
-
- template
- T GetValue(string const & key) const;
-
- template
- void SetValue(string const key, T const & value);
-
-private:
- map m_data;
-};
DECLARE_EXCEPTION(XMLFeatureError, RootException);
class XMLFeature
{
public:
- XMLFeature() = default;
- static XMLFeature FromXMLDocument(pugi::xml_document const & document);
+ XMLFeature();
+ XMLFeature(string const & xml);
- bool ToXMLDocument(pugi::xml_document & document) const;
+ pugi::xml_document const & GetXMLDocument() const;
- m2::PointD GetCenter() const { return m_center; }
- void SetCenter(m2::PointD const & center) { m_center = center; }
+ m2::PointD GetCenter() const;
- string const & GetInternationalName() const { return m_internationalName; }
- void SetInterationalName(string const & name) { m_internationalName = name; }
+ string const GetName(string const & lang = "") const;
+ string const GetName(uint8_t const langCode) const;
- StringUtf8Multilang const & GetMultilangName() const { return m_name; }
- void SetMultilungName(StringUtf8Multilang const & name) { m_name = name; }
+ string const GetHouse() const;
- StringNumericOptimal const & GetHouse() const { return m_house; }
- void SetHouse(StringNumericOptimal const & house) { m_house = house; }
+ time_t GetModificationTime() const;
- time_t GetModificationTime() const { return m_timestamp; }
- void SetModificationTime(time_t const timestamp) { m_timestamp = timestamp; }
+ bool HasTag(string const & key) const;
- bool HasTag(string const & key) const { return m_tags.find(key) == end(m_tags); }
-
- string GetTagValue(string const & key) const {
- return HasTag(key) ? m_tags.find(key)->second : "";
- }
-
- void SetTagValue(string const key, string const & value) { m_tags[key] = value; }
+ string GetTagValue(string const & key) const;
private:
- m2::PointD m_center;
-
- string m_internationalName;
- StringUtf8Multilang m_name;
- StringNumericOptimal m_house;
-
- // TODO(mgsergio): It could be useful to have separate class
- // for this
- // uint32_t m_types[m_maxTypesCount];
-
- // string version; // Duno, may prove useful
-
- time_t m_timestamp;
- map m_tags;
+ unique_ptr m_documentPtr;
};
} // namespace indexer