Search code examples
c++boostboost-propertytree

Select a sub node tag regardless the position using boost::property_tree


Let's say I have two XMLs:

<some><non_important><header><my_value>foo</my_value></header></non_important></some>
<some_1><non_important_1><header_1><my_value>foo</my_value></header_1></non_important_1></some_1>

Is there a way to extract my_value from both xml using property tree without specifying the absolute path?

The best that I can do at the moment is:

std::string first("some.non_important.header.my_value");
std::string second("some_1.non_important_1.header_1.my_value");

std::string getMyValue(std::istream& xml,const std::string& path)
{
    pt::ptree tree;
    pt::read_xml(xml, tree);
    return tree.get<std::string>(path);
}

I guess I am looking for is the equivalent of "//" in XPath.


Solution

  • Just traverse the tree, recursively:

    Live On Coliru

    #include <boost/property_tree/xml_parser.hpp>
    #include <iostream>
    
    using Ptree = boost::property_tree::ptree;
    //template <typename Ptree>
    bool read_from(std::string& into, Ptree const& pt, std::string const& target) {
        if (auto v = pt.get_optional<std::string>(target)) {
            into = *v;
            return true;
        }
        for (auto& child : pt) {
            if (read_from(into, child.second, target)) return true;
        }
    
        return false;
    }
    
    int main() {
        for (auto text : {
            "<some><non_important><header><my_value>foo</my_value></header></non_important></some>",
            "<some_1><non_important_1><header_1><my_value>foo</my_value></header_1></non_important_1></some_1>",
        })
        {
            boost::property_tree::ptree pt;
            {
                std::istringstream iss(text);
                read_xml(iss, pt);
            }
    
            std::string my_value;
            if (read_from(my_value, pt, "my_value")) {
                std::cout << "Retrieved value: " << my_value << "\n";
            }
        }
    }
    

    Prints

    Retrieved value: foo
    Retrieved value: foo