45

I'm trying to write an XML parser, parsing the XML file to a boost::property_tree and came upon this problem. How can I check (quickly) if a child of a certain property exists?

Obviously I could iterate over all children using BOOST_FOREACH - however, isn't there a better solution to this?

Null
  • 1,950
  • 9
  • 30
  • 33
paul23
  • 8,799
  • 12
  • 66
  • 149
  • While these solutions might appear to avoid iterating over the tree, just keep in mind that under the covers they are still doing exactly that, so you are making your algorithm potentially n^2... if you are concerned about performance and have memory to spare, you could use a map container for quick lookups. – Rich Jul 23 '14 at 15:28

5 Answers5

57
optional< const ptree& > child = node.get_child_optional( "possibly_missing_node" );
if( !child )
{
  // child node is missing
}
RobH
  • 3,199
  • 1
  • 22
  • 27
  • in order to get your example to work I had to remove the 'const' - could you please explain why you use 'const' here ? – serup Sep 14 '16 at 08:43
  • For safety. When reading configuration there can be little reason ever to modify values. A quick search shows me that ptree still has (in boost 1.61.0) a get_child_optional overload which returns optional, so your error will be related to what you do with the value subsequently. – RobH Sep 19 '16 at 10:33
  • 1
    I tried several alternatives and ended up using boost::optional. Note that you can also access the data directly using the code from the Boost documentation: See [Boost docs here](https://www.boost.org/doc/libs/1_41_0/doc/html/boost_propertytree/accessing.html). Try this: boost::optional v = pt.get_optional("a.path.to.float.value"); – eatyourgreens Jun 11 '18 at 08:35
25

Here's a couple of other alternatives:

if( node.count("possibliy_missing") == 0 )
{
   ...
}

ptree::const_assoc_iterator it = ptree.find("possibly_missing");
if( it == ptree.not_found() )
{
   ...
}
Michael Anderson
  • 70,661
  • 7
  • 134
  • 187
  • 3
    I like the 2nd one ... more stl style – anhoppe Nov 10 '15 at 08:52
  • 1
    I find it interesting to note that unlike the get<> method the find method does not provide support for find("SubNode.Attribute"). You have to manually get the SubNode child in the ptree and run find on the child instance, – anhoppe Nov 10 '15 at 10:21
  • 2
    node.count will also not work for nested keys, such as "child.subchild". The only thing that I found works so far is the node.get_child_optional, as in the below answer https://stackoverflow.com/a/25389349/844728 – Greg Kramida Nov 14 '19 at 10:26
  • From previous comments it looks like `find()` is the fastest way to check existence of immediate children, as the function doesn't have to split a path (compare with `get_child_optional()`, which does). – zett42 Jun 08 '22 at 10:34
6

Include this:

#include <boost/optional/optional.hpp>

Remove the const:

boost::optional< ptree& > child = node.get_child_optional( "possibly_missing_node" );
if( !child )
{
  // child node is missing
}
Avery
  • 2,270
  • 4
  • 33
  • 35
  • 6
    While your answer is valid, you copied most of another answer (with no disclosure!) that was accepted and almost 3 years old. Can you at least explain why you made the changes you did? This is likely better served as a comment. – Avery Aug 19 '14 at 17:28
  • 2
    I voted you down since you are not adding to the solution - perhaps if you had changed more than just removing the const, then I would have voted up – serup Sep 14 '16 at 09:19
0

One other way which can be used is to used in case you don't want to check some potential missing child/nodes. Try using iterators:

if (node.begin() != node.end()) { // Node does have child[ren]
     // Code to process child nodes
}
  • That's not what's being asked here – Mad Physicist May 19 '22 at 15:25
  • @MadPhysicist Although its not what was exactly asked its pretty elegant in case you just need to find if a node has child nodes. I needed exactly this in distinguishing json array element from non-array element. I upvoted it. – devbin Feb 13 '23 at 22:00
  • @devbin. I'm a huge fan of the voting system here: I didn't like the answer, so I downvoted; you liked it and upvoted. Both of us got to present valid reasons, and everyone can move on with their projects. – Mad Physicist Feb 13 '23 at 22:02
0

You can check if a tag is present or not using count()

typedef boost::property_tree pt;
pt::ptree tree;
pt::read_xml(filename, tree);

int bodyCount = tree.count( "body" );

if( bodyCount == 0 )
{
  cout<<"Failed : body tag not found"<<endl;
  return -1;
}