Recursively Search ValueTree


#1

When opening a file to input new values into the value tree from XML, I would like to be able to recursively search the tree (i.e. check all the sibling trees for properties) to see which values have changed and set the new properties accordingly. Currently I just have a mess of nested for and if statements which checks for the number of children on the current tree, obtains the properties of the current tree and then checks if it has any children (repeating the process if it does). Is there a method in JUCE I’ve missed which will provide similar functionality in a more efficient or visually cleaner way to recursively search a ValueTree?

edit: For anybody interested, I cleaned it all up into a function (below) which returns the list of properties as a vector and prints the list of properties to the console for debugging purposes.

std::vector<String> MyoMapperApplication::searchTree (juce::ValueTree tree)
{
    std::vector<String> propertyList;
    for (int i = 0; i < tree.getNumChildren(); ++i)
    {
        auto childTree = tree.getChild (i);
        for (int j = 0; j < childTree.getNumProperties(); ++j)
        {
            auto propertyName = childTree.getPropertyName(j);
            auto property = childTree.getProperty (propertyName);
            propertyList.push_back (childTree.getProperty (name).toString() + ": " + property.toString() + newLine);
        }
        if (childTree.getNumChildren() != 0)
        {
            searchTree (childTree);
        }
    }
    for (auto i = propertyList.begin(); i != propertyList.end(); ++i)
    {
        DBG (*i);
    }
    return propertyList;
}

#2
void searchTree(juce::ValueTree tree, const juce::Identifier& propertyToSearchFor)
{
	for (auto& child : tree)
	{
		if (child.getPropertyPointer(propertyToSearchFor) != nullptr)
		{
			DBG(propertyToSearchFor + ": " + child.getProperty(propertyToSearchFor));
		}

		searchTree(child, propertyToSearchFor);
	}
}

Something like this ? (not tested)

There is also
ValueTree::getChildWithProperty (const Identifier& propertyName, const var& propertyValue)
if you specifically look for matching property values.


#3

Using this method, how would you know how many depths of sibling to search for? Where would you define ‘child’?


#4

Well, you would not know how many. It just recursively walks every subtree it can find.

‘child’ is defined in the for loop (c++11)
for (auto& child : tree)


#5

I should really get to grasps with some of these C++11 features! I’ll give the code a test in the morning


#6

Here’s how a pro would write something like that :slight_smile:

template <typename Function>
static void applyFunctionRecursively (const ValueTree& tree, const Function& function)
{
    function (tree);

    for (auto&& child : tree)
        applyFunctionRecursively (child, function);
}

applyFunctionRecursively (myTree, [] (const ValueTree& v)
{
    if (auto* p = v.getPropertyPointer (propertyToSearchFor))
        DBG (propertyToSearchFor << ": " << p->toString());
});

#7

Noob question, why use a template for this rather than the way Seba uses above?


#8

What he wrote is fine as a function to do one specific task - I was just showing how you could abstract the tree recursion from the task you want to apply to each element.