使用 Boost 属性树解析 SVG (XML)
Posted
技术标签:
【中文标题】使用 Boost 属性树解析 SVG (XML)【英文标题】:Parsing SVG (XML) with Boost Property Tree 【发布时间】:2012-11-13 03:51:08 【问题描述】:我正在尝试使用 Boost C++ 的 ptree 解析以下 SVG (XML) 标记...
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 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" 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>
C++ 代码:
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;
输出:
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
问题:
它编译得很好,但它没有选择M 10 100 L 10 140 L 89 131 L 324 2 Z
条目。为什么第二个BOOST_FOREACH
不遍历每个<path>
和cout
。
【问题讨论】:
【参考方案1】:第二个 BOOST_FOREACH 正在调用 g.get_child("path")
,它返回 g
的第一个子元素 path
。您需要使用您要查找的密钥遍历所有子项。
这可以通过以下方式实现:
/** 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;
例如
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";
我发现以下代码在使用 ptree 时很有用,它将显示您解析的整个 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 );
【讨论】:
太棒了。效果很好,非常感谢!我想我只是对get_child('svg')
返回所有 svg 的孩子感到困惑,但是,get_child('path')
只会返回第一个。也感谢您的display_ptree
,很棒的调试工具。以上是关于使用 Boost 属性树解析 SVG (XML)的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 boost 属性树提取 xml 文件的 DOCTYPE 节点?