Дерево свойств напоминает (почти является) стандартный контейнер со значением типа<pair<string,ptree>
>. Он имеет обычные членские функции, такие как<insert
>,<push_back
>,<find
>,<erase
>и т.д. Конечно, их можно использовать для заселения и доступа к дереву. Например, следующий код добавляет ключ<"pi"
>с данными (почти) равными математическомупизначению:
ptree
pt;
pt.push_back
(ptree
::value_type
("pi", ptree
("3.14159")));
Чтобы найти значение<pi
>, мы можем сделать следующее:
ptree
::const_iterator
it = pt.find
("pi");
double pi = boost::lexical_cast<double>(it->second.data
());
Это выглядит довольно громоздко, и было бы еще более обременительно, если бы<pi
>значение не хранилось так близко к вершине дерева, и мы немного больше заботились об ошибках. К счастью, есть другой, правильный способ сделать это:
ptree pt;
pt.put
("pi", 3.14159);
double pi = pt.get
<double>("pi");
Всё не становится проще. В основном, существует 2 семейства функций-членов,<get
>и<put
>, которые позволяют интуитивно получать доступ к данным, хранящимся в дереве (прямые дети или нет).
Существует три версии get: get, get (версия по умолчанию) и get_optional, которые отличаются стратегией обработки отказов. Все версии имеют спецификатор пути, который определяет, в каком ключе искать значение. Это может быть один ключ или путь к ключу, где элементы пути разделены особым характером (а.), если не указано иначе. Например, debug.logging.errorlevel может быть действительным путем с точкой в качестве разделителя.
Бросающая версия<get
>:
ptree
pt;
Этот вызов находит правильный узел в дереве и пытается перевести свою строку данных в плавающее значение. Если это не удается, исключение отбрасывается. Если же пути нет, то это исключение<ptree_bad_path
>. Если бы не перевод, это было бы<ptree_bad_data
>. Оба они исходят из<ptree_error
>, чтобы сделать возможным общее обращение.
Версия по умолчанию<get
>:
ptree
pt;
Он будет делать то же самое, что и выше, но если он выйдет из строя, он вернет значение по умолчанию, указанное вторым параметром (здесь -1.f), вместо того, чтобы бросать. Это очень полезно в обычных ситуациях, когда нужно пропустить некоторые ключи. Обратите внимание, что спецификация типа, необходимая в бросочной версии, обычно не требуется здесь, потому что тип определяется параметром значения по умолчанию.
Факультативная версия<get_optional
>:
;повышение::факультативное<поплавок>v=pt<поплавок>
В этой версии используется boost::optional class для решения проблемы извлечения. При успешной экстракции он будет возвращать импульс:: необязательно инициализированный с извлеченным значением. В противном случае он вернет неинициализированный импульс:
Чтобы извлечь значение из этого дерева (не какой-то подключ), используйте<get_value
>,<get_value
>(версия по умолчанию) и<get_value_optional
>. Они имеют идентичную семантику с функциями<get
>, за исключением того, что они не принимают параметр<path
>. Не звоните<get
>с пустым<path
>, чтобы сделать это, поскольку он попытается извлечь содержимое подключа с пустым именем.
Чтобы использовать символ сепаратора, отличный от по умолчанию<.
>, вам нужно явно построить объект пути. Тип пути для<ptree
>представляет собой инстанциацию струнного пути, поэтому самый простой способ обратиться к нему —<ptree
>::path_type. Таким образом, вы можете использовать деревья с точками в ключах:
typedef ptree::path_type path;
pt.get<float>(path("p.a.t.h/t.o/v.a.l.u.e", '/'));
pt.get(path("p.a.t.h/t.o/v.a.l.u.e", '/'), 0, NULL);
pt.get_optional<std::string>(path("p.a.t.h/t.o/v.a.l.u.e", '/'));
Примечание: специальные перегрузки<get
>и<get_optional
>с использованием сепаратора, которые существовали в предрелизных версиях PropertyTree, были удалены. Это связано с тем, что перегрузки конфликтовали с использованием переводчиков данных по вызову.
В дополнение к<get
>есть<put
>и<add
>. В отличие от<get
>, они имеют только один вариант. Это связано с тем, что нет необходимости иметь дело с отсутствующими значениями при добавлении данных. Если подаваемое значение не может быть преобразовано в тип данных дерева, функции будут отбрасывать<ptree_bad_data
>.
ptree
pt;
pt.put
("a.path.to.float.value", 3.14f);
pt.put
("a.path.to.float.value", 2.72f);
pt.add
("a.path.to.float.value", 3.14f);
Звонок<put
>будет вставлять новое значение на указанном пути, так что вызов на<get
>, указывающий тот же путь, будет извлекать его. Кроме того,<put
>будет вставлять любые недостающие элементы пути во время прохождения. Например, вызов<put("key1.key2.key3",3.14f)
>на пустое дерево вставит трех новых детей:<key1
>,<key1.key2
>и<key1.key2.key3
>. Последний получит строку<"3.14"
>в качестве данных, а два предыдущих будут иметь пустые строки данных.<put
>всегда вставляет новые ключи в заднюю часть существующих последовательностей. Разница между<put
>и<add
>заключается в том, что ставить будет перезаписывать существующие значения, если они есть, в то время как добавить будет создавать новый узел для удержания значения, даже если указанный путь ссылается на существующий узел.
Подобно<get_value
>, существует также<put_value
>функция. Он делает то же самое для этого дерева свойств, что делает для его детей<put
>. При этом он не получает<path
>:
ptree
pt;
pt.put_value
(3.14f);
Функция add_value отсутствует.