Frage

I'm attempting to parse the following SVG (XML) markup with Boost C++'s ptree...

The SVG (XML)

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg height="395.275590551181" version="1.1"
     viewBox="0 0 757.48031496063 395.275590551181" xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink" style="background-color: #ffffff;">
<desc>Some Description</desc>
<g visibility="hidden" pointer-events="all">
    <rect x="0" y="0" width="100%" height="100%" fill="none" />
</g>
<g>
    <path d="M 5 56 L 5 14 L 8 11 L 34 11 Z" />
    <path d="M 10 100 L 10 140 L 89 131 L 324 2 Z" />
</g>
<g>
    <path d="M 20 130 L 1 1 L 89 130 L 34 2 Z" />
</g>
</svg>

The C++ Code:

    typedef boost::property_tree::ptree::value_type vt;
    boost::property_tree::ptree root;
    read_xml("My_SVG.svg", root);
    BOOST_FOREACH (vt const &nodes, root.get_child("svg")) {
        //only action on g's and not desc, comments, etc.
        if(nodes.first=="g"){
            boost::property_tree::ptree g = nodes.second;
            //only action on g's that contain paths, not g->rect, for example.
            if(g.count("path") != 0){
                BOOST_FOREACH (vt const &p, g.get_child("path")) {
                    std::cout << p.second.get("d", "false") << std::endl;
                }
            }
        }
    }

The Output:

M 5 56 L 5 14 L 8 11 L 34 11 Z
M 20 130 L 1 1 L 89 130 L 34 2 Z

The Problem:

It compiles fine but it's not picking up the M 10 100 L 10 140 L 89 131 L 324 2 Z entry. Why doesn't the second BOOST_FOREACH step through each <path> and cout it.

War es hilfreich?

Lösung

The second BOOST_FOREACH is calling g.get_child("path") which returns the first child of g called path. You need to iterate over all of the children with the key that you are looking for.

This can be achieved using:

/** Find the range of children that have the given key. */
std::pair<assoc_iterator, assoc_iterator> 
   ptree::equal_range(const key_type &key);

/** Count the number of direct children with the given key. */
size_type count(const key_type &key) const;

e.g.

  typedef boost::property_tree::ptree::value_type vt;
BOOST_FOREACH (vt const &nodes, pt.get_child("svg")) 
{
    //only action on g's and not desc, comments, etc.
    if(nodes.first=="g")
    {
        const boost::property_tree::ptree& g = nodes.second;
        //only action on g's that contain paths, not g->rect, for example.
        if(g.count("path") != 0)
        {
            std::pair< ptree::const_assoc_iterator,
                       ptree::const_assoc_iterator > bounds = g.equal_range( "path" );

            for( ptree::const_assoc_iterator it = bounds.first; it != bounds.second; ++it )
            {
                std::cout  << it->first << " : ";

                const ptree& d = it->second.get_child( "<xmlattr>.d" );
                std::cout << d.get_value<std::string>() << "\n";
            }
        }
    }
}

I find the following code useful when working with ptree, it will display your entire parsed ptree:

void display_ptree(ptree const& pt)
{
    BOOST_FOREACH( const ptree::value_type& v, pt )
    {e 
        std::cout << v.first << ": " << v.second.get_value<std::string>() << "\n";
        display_ptree( v.second );
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top