iterate through boost property tree
Asked Answered
M

1

6

I'm iterating over an XML document using boost property tree and storing the results in a struct. The issue I have is that I can only get to the first "item" nodes and can't access the second "item" nodes. I was hoping someone would point out where I've made a mistake.

My program output looks like this (you can see items are missing.. there is no cookie2, candy2 or chocolate2 items shown):

jar : snAcks
snack : coOkie
item : cooKie1
snack : canDy
item : caNdy1
snack : cHocolate
item : choColate1

Here's the xml file:

<root>
    <jar name="snAcks">
        <snack name="coOkie">
           <item name="cooKie1"></item>
           <item name="cookIe2"></item>
        </snack>
        <snack name="canDy">
           <item name="caNdy1"></item>
           <item name="candY2"></item>
        </snack>
        <snack name="cHocolate">
           <item name="choColate1"></item>
           <item name="chocOlate2"></item>
        </snack>
    </jar>
</root>

Here's the source code:

void parse_xml( boost::property_tree::iptree const& pt )
{
    BOOST_FOREACH( boost::property_tree::iptree::value_type const& v, pt.get_child("root.jar") )
    {
        // Show jar
        if ( boost::iequals( v.first, "<xmlattr>" ) )
        {
            std::cout << "jar : " << v.second.get<std::string>("NaME") << std::endl;
        }

        if ( boost::iequals( v.first, "snack" ) )
        {
            // Show snack
            std::cout << "snack : " << v.second.get<std::string>("<xmlattr>.name")  << std::endl;

            try
            {
                BOOST_FOREACH( boost::property_tree::iptree::value_type const& val, v.second.get_child("item") )
                {
                    if ( boost::iequals( val.first, "<xmlattr>" ) ) {
                        // Show item
                        std::cout << "item : " << val.second.get<std::string>("nAmE")  << std::endl;
                    }
                }
            }

            catch (boost::property_tree::ptree_bad_path& e)
            {
                // Show what caused exception
                std::cout << "Exception: " << e.what() << std::endl;
            }
        }
    }
}

Thank you for taking time to read this. I think I've made a simple mistake, but cannot understand where.

Maximamaximal answered 9/2, 2012 at 17:49 Comment(2)
I added a bounty. I'd really like to know what I'm doing wrong here or if I need to look at other xml libraries. Thanks for any help!Maximamaximal
Maybe v.second.get_child("item") should just be v.second, or v.second.get_child("snack"): this question seems similar.Applicative
D
11

I figured it out, but this is not what i would call an intuitive xml-parser library.

void parse_xml( boost::property_tree::iptree const& pt )
{
    BOOST_FOREACH(boost::property_tree::iptree::value_type const& v, pt.get_child("root.jar"))
    {
        // Show jar
        if ( boost::iequals( v.first, "<xmlattr>" ) ) {
            std::cout << "jar : " << v.second.get<std::string>("NaME") << std::endl;
        }

        if ( boost::iequals( v.first, "snack" ) )
        {
            BOOST_FOREACH(boost::property_tree::iptree::value_type const& val, v.second)
            {
                // Show snack
                if ( boost::iequals( val.first, "<xmlattr>" ) ) {
                    std::cout << "snack : " << val.second.get<std::string>("name")  << std::endl;
                }

                if ( boost::iequals(val.first, "item") )
                {
                    BOOST_FOREACH(boost::property_tree::iptree::value_type const& val2, val.second)
                    if ( boost::iequals( val2.first, "<xmlattr>" ) ) {
                        // Show item
                        std::cout << "item : " << val2.second.get<std::string>("nAmE")  << std::endl;
                    }
                }
            }
        }
    }
}

If you compare the two code snippets you can see that mine is bit more regularly structured.

  1. Loop over all nodes
  2. process the <xmlattr> node
  3. process the "real" node.
  4. repeat from step 1. inside that node.
Dissimilation answered 2/3, 2012 at 20:28 Comment(3)
Thanks! That works. I can't award the bounty for awhile, but as soon as I can, it's yours. I really appreciate your time and advice!Maximamaximal
"this is not what i would call an intuitive xml-parser library." That's because property-tree is not an XML parser! That's not what it is for. It's designed for creating trees of properties and persisting them over time. You are not supposed to feed it arbitrary XML that it didn't generate. You're not supposed to use it as a quick-and-dirty XML parser.Sheehan
If you want a simple way to parse XML files in C++ I would recommend using libxml2 in conjunction with this c++ wrapper github.com/filipenf/libxml-cpp-wrapperYuu

© 2022 - 2024 — McMap. All rights reserved.