问题描述
我有大致相同的XML结构:
I have an XML structure along the lines of:
<root>
<SomeElement>
<AnotherElement>
<ElementIWant x="1" y="1"/>
</AnotherElement>
</SomeElement>
<SomeElement>
<AnotherElement>
<ElementIWant x="1" y="1"/>
<ElementIWant x="2" y="1"/>
<ElementIWant x="3" y="1"/>
</AnotherElement>
</SomeElement>
</root>
正在被读入的boost :: property_tree
,还有的 1..Many 的&LT; SomeElement&GT;
s,然后在该单元内任意深度有可能是的 1..Many 的&LT; ElementIWant&GT;
取值
Which is being read into a boost::property_tree
, There are 1..Many <SomeElement>
s, and then at an arbitrary depth within that element there could be 1..Many <ElementIWant>
s
有没有办法来遍历&LT; ElementIWant&GT;它们出现在文档的顺序
直接(在一个循环中)
Is there a way to iterate over the <ElementIWant>
directly (in a single loop) in the order that they appear in the doc?
我已经看过equal_range
I have looked at equal_range
void iterateOverPoints()
{
const char* test =
"<?xml version=\"1.0\" encoding=\"utf-8\"?><root>"
"<SomeElement>"
"<AnotherElement>"
"<ElementIWant x=\"1\" y=\"1\"/>"
"</AnotherElement>"
"</SomeElement>"
"<SomeElement>"
"<AnotherElement>"
"<ElementIWant x=\"1\" y=\"1\"/>"
"<ElementIWant x=\"2\" y=\"1\"/>"
"<ElementIWant x=\"3\" y=\"1\"/>"
"</AnotherElement>"
"</SomeElement>"
"</root>";
boost::property_tree::ptree message;
std::istringstream toParse(test);
boost::property_tree::read_xml(toParse,result_tree);
//Now we need to locate the point elements and set the x/y accordingly.
std::pair< boost::property_tree::ptree::const_assoc_iterator,
boost::property_tree::ptree::const_assoc_iterator > result =
message.equal_range("ElementIWant");
for( boost::property_tree::ptree::const_assoc_iterator it = result.first;
it != result.second; ++it )
{
std::cout << it->first << " : ";
const boost::property_tree::ptree& x = it->second.get_child( "<xmlattr>.x" );
const boost::property_tree::ptree& y = it->second.get_child( "<xmlattr>.y" );
std::cout << x.get_value<int>() << "," << y.get_value<int>() << "\n";
}
return;
}
但它似乎无法返回节点(我怀疑是因为equal_range工作在提供的树节点的水平)这使我想到上面的问题...
However it seems to fail to return nodes (Which I suspect is because equal_range works at the level of the tree node supplied) Which brings me to the question above...
推荐答案
这是不可能的所有元素直接迭代;
It is not possible to iterate over all elements directly; the documentation says
有没有办法来遍历整个树。
现在,你可以使用递归,并在每个级别模仿适用STL算法;它不适合你的我下面的示例中一个循环这样的要求,但它的作品:
Now, you could use recursion, and apply STL algorithms at each level to mimic that; it does not fit your requirement of doing this in a single loop in my sample below, but it does works:
template <typename InputIt, typename OutputIt, typename Compare>
void collect(InputIt first, InputIt last, OutputIt dest, Compare comp)
{
typedef typename std::iterator_traits<InputIt>::reference reference;
std::copy_if (
first, last, dest,
[comp] (reference what) { return comp(what.first); });
std::for_each (
first, last,
[dest, comp] (reference what) { collect(what.second.begin(), what.second.end(), dest, comp); });
}
std::vector<std::pair<std::string, ptree>> match;
collect(
xml.begin (), xml.end (), std::back_inserter(match),
[] (const std::string& key) { return key == "ElementIWant"; });
for (auto pair: match)
{
std::cout << pair.first << std::endl;
}
下面是一个版本是完全递归和preserve出现的顺序:
Here is a version that is "fully" recursive and preserve the order of appearance:
template <typename InputIt, typename OutputIt, typename Compare>
void collect_recursive(InputIt first, InputIt last, OutputIt dest, Compare comp)
{
typedef typename std::iterator_traits<InputIt>::reference reference;
if (first == last)
{
return;
}
auto begin = first->second.begin ();
auto end = first->second.end ();
if (begin != end)
{
collect_recursive (begin, end, dest, comp);
}
if (comp (first->first))
{
dest = *first;
}
collect_recursive (++first, last, dest, comp);
}
这篇关于如何遍历XML结构的boost :: property_tree的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!