Вместо того, чтобы пытаться строго набирать каждый узел в зависимости от количества его родителей, организуйте свой код в виде древовидной структуры:
class Element
{
public:
std::string Name;
std::map<std::string, std::string, std::less<std::string> > Attributes;
std::list<Element> Children;
};
Ваш публичный интерфейс, вероятно, будет сильно отличаться от этого. Я просто пытаюсь показать общий вид шрифта.
Вам на самом деле не нужны функции Node или Attribute, если вам не нужно перебирать их в коллекции вместе с Elements. Это полезная функция для библиотек XML DOM, но если вы просто пытаетесь создать структуру данных, вам не обязательно следовать букве DOM.
На самом деле, если вы просто собираетесь использовать общую структуру данных, вам может понадобиться пакет свойств:
#include<map>
#include<string>
#include<iostream>
class PropertyBag;
typedef std::map<std::string, PropertyBag> PropertyMap;
class PropertyBag : public PropertyMap
{
public:
PropertyBag(const std::string& value)
: value(value)
{
}
PropertyBag& operator=(const std::string& value)
{
this->value = value;
return *this;
}
operator std::string& () { return value; }
private:
std::string value;
friend PropertyMap::mapped_type& PropertyMap::operator[](const PropertyMap::key_type&);
PropertyBag() { }
};
void SomeFunction(const std::string& value)
{
std::cout << value << "\n";
}
int main(int argc, char* argv[])
{
PropertyBag config("configuration root");
config["child1"] = "value1";
config["child1"]["subchild1"] = "value2";
SomeFunction(config["child1"]);
SomeFunction(config["child1"]["subchild1"]);
return 0;
}
Просто говоря о синтаксисе, вы также можете попытаться запутаться с перегрузкой operator()
и / или с цепочечными методами:
PropertyBag& SomeMethod(const std::string& someParam)
{
// do something here...
return *this;
}
PropertyBag& operator()(const std::string& p1, const std::string& p2)
{
// ...
return *this;
}
// ...
Configuration config1("root")
.SomeMethod("p1")
.SomeMethod("p2");
Configuration config2("root")
("Something", "blah")
("sizzle", "V2");
Я представляю, чем меньше дублирования текста / кода, тем лучше. Чем ближе ваш код будет иметь синтаксис, такой как JSON или YAML, тем лучше.
Когда выйдет c ++ 0x, у вас могут появиться гораздо более простые варианты. Вы также можете заглянуть в библиотеку boost :: assign для простого синтаксиса инициализации, используемого в вашей структуре данных.
Вы также можете найти в boost :: any library тип данных, который можно использовать в качестве значения вместо строк (поддерживает безопасный для ввода метод вставки любого значения, если распакуйте его как тот же тип).