2 #include <rapidxml/rapidxml.hpp>
3 #include <rapidxml/rapidxml_print.hpp>
17 std::ifstream ifs(file);
18 assert_msg(ifs.good(),
"Failed opening file '%s' with error: %s.", file, strerror(errno));
19 ifs.seekg(0, std::ios::end);
20 std::size_t length = ifs.tellg();
21 ifs.seekg(0, std::ios::beg);
31 }
catch (
const rapidxml::parse_error& e) {
32 std::cerr <<
"Error parsing file contents '"
33 <<
static_cast<const char*
>(
file_contents.data()) <<
"'." << std::endl;
50 os <<
"XML document: '\n";
51 rapidxml::print(os, xml.
doc, 0);
55 std::pair<std::vector<std::string>, std::string>
XML::splitPath(std::string path) {
56 assert_msg(!path.empty(),
"Path name should not be empty.");
57 std::size_t last_dot_idx = path.find_last_of(
'.');
58 if (last_dot_idx == std::string::npos) {
61 std::string attribute_name = path.substr(last_dot_idx+1);
62 assert_msg(!attribute_name.empty(),
"Path '%s' contains an empty attribute name.", path);
64 path = path.substr(0, last_dot_idx);
65 std::vector<std::string> split_path;
68 std::size_t new_idx = path.find(
'.', idx);
69 if (new_idx == std::string::npos) { new_idx = path.size(); }
70 assert_msg(new_idx - idx > 0,
"Path '%s' contains an empty element name.", path);
71 split_path.push_back(path.substr(idx, new_idx-idx));
73 }
while (idx <= path.size());
74 return {split_path, attribute_name};
77 std::string
XML::join(
const std::vector<std::string>& path) {
78 if (path.empty()) {
return ""; }
79 std::string r = path[0];
80 for (std::string::size_type i = 1; i < path.size(); ++i) {
88 const std::string& attribute_name)
const {
89 rapidxml::xml_node<char>* root =
doc.first_node();
90 for (
const auto& name : path) {
91 root = root->first_node(name.c_str(), name.size());
92 assert_msg(root !=
nullptr,
"Element '%s' from path '%s' not found.",
95 auto* attr = root->first_attribute(attribute_name.c_str(), attribute_name.size());
96 assert_msg(attr !=
nullptr,
"Attribute '%s', specified by path '%s' not found.",
97 attribute_name,
join(path));
101 void XML::setString(
const std::vector<std::string>& path,
const std::string& attribute_name,
102 const std::string& content) {
103 rapidxml::xml_node<char>* root =
doc.first_node();
104 for (
const auto& name : path) {
105 auto* child = root->first_node(name.c_str(), name.size());
106 if (child ==
nullptr) {
107 char* node_name =
doc.allocate_string(name.c_str());
108 child =
doc.allocate_node(rapidxml::node_element, node_name);
109 root->append_node(child);
113 auto* attr = root->first_attribute(attribute_name.c_str(), attribute_name.size());
114 if (attr ==
nullptr) {
115 char* attr_name =
doc.allocate_string(attribute_name.c_str());
116 attr =
doc.allocate_attribute(attr_name);
117 root->append_attribute(attr);
119 assert_msg(attr !=
nullptr,
"Attribute '%s' not found on path '%s'.",
120 attribute_name,
join(path));
121 char* attr_content =
doc.allocate_string(content.c_str());
122 attr->value(attr_content);
127 std::string XML::get<std::string>(
const std::string& path)
const {
128 std::vector<std::string> path_elements;
129 std::string attribute_name;
130 std::tie(path_elements, attribute_name) = splitPath(path);
131 return getString(path_elements, attribute_name);
135 void XML::set<std::string>(
const std::string& path,
const std::string& value,
bool overwrite) {
136 std::vector<std::string> path_elements;
137 std::string attribute_name;
138 std::tie(path_elements, attribute_name) = splitPath(path);
140 assert_msg(!exists(path),
"Attribute on path '%s' already exists with value '%s'. "
141 "Set overwrite=true to overwrite its value.",
142 path, getString(path_elements, attribute_name));
144 setString(path_elements, attribute_name, value);
148 std::vector<std::pair<std::string, std::string>>
XML::getAll()
const {
149 std::vector<std::pair<std::string, std::string>> all_attributes;
151 return all_attributes;
155 std::vector<std::pair<std::string, std::string>>& all_attr)
const {
156 for (
const auto* a = node->first_attribute(); a; a = a->next_attribute()) {
157 all_attr.emplace_back(path+a->name(), a->value());
159 for (
const rapidxml::xml_node<>* n = node->first_node(); n; n = n->next_sibling()) {
165 rapidxml::xml_node<char>* root =
doc.first_node();
166 std::vector<std::string> path_elements;
167 std::string attribute_name;
168 std::tie(path_elements, attribute_name) =
splitPath(path);
169 for (
const auto& element_name : path_elements) {
170 root = root->first_node(element_name.c_str(), element_name.size());
171 if (!root)
return false;
173 auto* attr = root->first_attribute(attribute_name.c_str(), attribute_name.size());
174 return attr !=
nullptr;