Я получаю значения моего файла конфигурации с rapidXML любезно плохим способом.
xml_document<> doc;
doc.parse<parse_full>(buffer);
int a = atoi(doc.first_node("master")->first_node("profile")->first_node("width")->value());
Если узел не существует, «first_node» возвращает 0, поэтому «-> value ()» вылетает. Возврат нового xml_node исправит сбой, но как насчет утечек памяти?
Это функция rapidXML со старым и новым возвратом:
xml_node<Ch> *first_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
{
if (name)
{
if (name_size == 0)
name_size = internal::measure(name);
for (xml_node<Ch> *child = m_first_node; child; child = child->next_sibling())
if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive))
return child;
return new xml_node<Ch>(node_document);
//return 0;
}
else
return m_first_node;
}
Вы должны использовать исключения, такие как:
int a;
try
{
xml_document<> doc;
doc.parse<parse_full>(buffer);
a = atoi(doc.first_node("master")->first_node("profile")->first_node("width")->value());
}
catch(NodeNotExists &ex)
{
// process error condition
}
Кроме того, если вы не хотите изменять код rapidxml, используйте функцию-обертку, например:
template<typename T>
T* notnull(T* arg)
{
if (arg == 0)
throw NodeNotExists();
return arg;
}
Расширяя ответ hate-engine, я создал класс статических вспомогательных функций, чтобы справиться с этой ситуацией, обернув доступ к значению узла. Проверьте мой ответ Вот. Вы можете расширить это или заняться чем-то более похожим на xpath-стиль доступа к узлам (который я не считаю встроенным в RapidXML в настоящее время, но другие делают).
Редактировать: Вы можете создать функцию-обёртку, которая принимает простой путь, похожий на xpath, и комбинировать его с одним из моих обёрток, чтобы получить что-то вроде …
int a = GetNodeInt(GetFirstNodePath(doc, "master/profile/width"), 0);
Где GetNodeInt и GetFirstNodePath определены примерно так:
int GetNodeInt(rapidxml::xml_base<>* node, int DefaultValue)
{
int temp;
try
{
if (node == 0) return DefaultValue;
if (sscanf(node->value(), "%d", &temp) != 1) return DefaultValue;
return temp;
}
catch (...) { return DefaultValue; }
}
// Find node with simple path from current node such as "first/second/third"rapidxml::xml_node<>* GetFirstNodePath(rapidxml::xml_node<>* root, const char *path)
{
xml_node<>* node = root;
char* last = (char*)path; // only using this pointer to read
char* cur = last;
if (cur == 0 || root == 0) return 0;
while (node)
{
if (*cur == '/' || *cur == 0)
{
if (cur != last) node = node->first_node(last,cur-last);
if (*cur == 0) break;
last = cur + 1;
}
++cur;
}
return node;
}
Сейчас этот код не был тщательно протестирован, но дает вам общее представление.