#ifndef PUGIXML_UTIL_H #define PUGIXML_UTIL_H /* * This file contains utilities for the PUGI XML parser. * * They primarily relate to: * - Checking for node/attribute exitance and reporting errors if not * - Misc. utilities like counting tags * * Using these utilities simplifies error handling while manipulating XML * since the user doesn't need to explicitly check for node/attribute existance * (by default most of these functions will raise exceptions with useful error * messages if the requested item does not exists). */ #include #include #include #include "pugixml.hpp" #include "pugixml_loc.hpp" namespace pugiutil { //An error produced while getting an XML node/attribute class XmlError : public std::runtime_error { public: XmlError(std::string msg = "", std::string new_filename = "", size_t new_linenumber = -1) : std::runtime_error(msg) , filename_(new_filename) , linenumber_(new_linenumber) {} //Returns the filename associated with this error //returns an empty string if none is specified std::string filename() const { return filename_; } const char* filename_c_str() const { return filename_.c_str(); } //Returns the line number associated with this error //returns zero if none is specified size_t line() const { return linenumber_; } private: std::string filename_; size_t linenumber_; }; //Loads the XML file specified by filename into the passed pugi::xml_docment // //Returns loc_data look-up for xml node line numbers loc_data load_xml(pugi::xml_document& doc, //Document object to be loaded with file contents const std::string filename); //Filename to load from //Defines whether something (e.g. a node/attribute) is optional or required. // We use this to improve clarity at the function call site (compared to just // using boolean values). // // For example: // // auto node = get_first_child(node, "port", loc_data, true); // // is ambiguous without looking up what the 4th argument represents, where as: // // auto node = get_first_child(node, "port", loc_data, REQUIRED); // // is much more explicit. enum ReqOpt { REQUIRED, OPTIONAL }; //Gets the first child element of the given name and returns it. // // node - The parent xml node // child_name - The child tag name // loc_data - XML file location data // req_opt - Whether the child tag is required (will error if required and not found) or optional. Defaults to REQUIRED pugi::xml_node get_first_child(const pugi::xml_node node, const std::string& child_name, const loc_data& loc_data, const ReqOpt req_opt = REQUIRED); //Gets the child element of the given name and returns it. //Errors if more than one matching child is found. // // node - The parent xml node // child_name - The child tag name // loc_data - XML file location data // req_opt - Whether the child tag is required (will error if required and not found) or optional. Defaults to REQUIRED pugi::xml_node get_single_child(const pugi::xml_node node, const std::string& child_name, const loc_data& loc_data, const ReqOpt req_opt = REQUIRED); //Counts the number of child nodes of type 'child_name' // // node - The parent xml node // child_name - The child tag name // loc_data - XML file location data // req_opt - Whether the child tag is required (will error if required and not found) or optional. Defaults to REQUIRED size_t count_children(const pugi::xml_node node, const std::string& child_name, const loc_data& loc_data, const ReqOpt req_opt = REQUIRED); //Counts the number of child nodes (any type) // // node - The parent xml node // loc_data - XML file location data // req_opt - Whether the child tag is required (will error if required and not found) or optional. Defaults to REQUIRED size_t count_children(const pugi::xml_node node, const loc_data& loc_data, const ReqOpt req_opt); //Throws a well formatted error if the actual count of child nodes named 'child_name' does not equal the 'expected_count' // // node - The parent xml node // loc_data - XML file location data // expected_count - The expected number of child nodes void expect_child_node_count(const pugi::xml_node node, std::string child_name, size_t expected_count, const loc_data& loc_data); //Throws a well formatted error if the actual child count does not equal the 'expected_count' // // node - The parent xml node // loc_data - XML file location data // expected_count - The expected number of child nodes void expect_child_node_count(const pugi::xml_node node, size_t expected_count, const loc_data& loc_data); //Throws a well formatted error if any of node's children are not part of child_names. //Note this does not check whether the nodes in 'child_names' actually exist. // // node - The parent xml node // child_names - expected attribute names // loc_data - XML file location data void expect_only_children(const pugi::xml_node node, std::vector child_names, const loc_data& loc_data); //Throws a well formatted error if any attribute other than those named in 'attribute_names' are found on 'node'. //Note this does not check whether the attribues in 'attribute_names' actually exist. // // node - The parent xml node // attribute_names - expected attribute names // loc_data - XML file location data void expect_only_attributes(const pugi::xml_node node, std::vector attribute_names, const loc_data& loc_data); //Throws a well formatted error if any attribute other than those named in 'attribute_names' are found on 'node' with an additional explanation. //Note this does not check whether the attribues in 'attribute_names' actually exist. // // node - The parent xml node // attribute_names - expected attribute names // loc_data - XML file location data void expect_only_attributes(const pugi::xml_node node, std::vector attribute_names, std::string explanation, const loc_data& loc_data); //Counts the number of attributes on the specified node // // node - The xml node // loc_data - XML file location data // req_opt - Whether any attributes are required (will error if required and none are found) or optional. Defaults to REQUIRED size_t count_attributes(const pugi::xml_node node, const loc_data& loc_data, const ReqOpt req_opt = REQUIRED); //Gets a named property on an node and returns it. // // node - The xml node // attr_name - The attribute name // loc_data - XML file location data // req_opt - Whether the attribute is required (will error if required and not found) or optional. Defaults to REQUIRED pugi::xml_attribute get_attribute(const pugi::xml_node node, const std::string& attr_name, const loc_data& loc_data, const ReqOpt req_opt = REQUIRED); //Checks that the given node matches the given tag name. // // node - The xml node // tag_name - The expected tag name // loc_data - XML file location data // req_opt - Whether the tag name is required (will error if required and not found) or optional. Defaults to REQUIRED bool check_node(const pugi::xml_node node, const std::string& tag_name, const loc_data& loc_data, const ReqOpt req_opt = REQUIRED); } // namespace pugiutil #endif