CalcEngine Plus

User-authored calculations for .NET

Implementing Hierarchy Support

In many applications, calculations are embodied in some form of hierarchical structure. When this is the case, it’s a natural desire to have a parent node that represents the sum of all the child nodes, or perhaps the max/min of all the child nodes. The user will have a natural expectation that they can add and remove nodes from the tree, and any aggregate calculations defined on a parent will “just keep working”.

CalcEngine Plus supports this via the keyword “children”. This enables expressions like “sum(children)” and “avg(children)”. In a hierarchical context, the “children” keyword is understood to mean “all the entities that are immediate descendants of this parent”.

Of course, to support the “children” keyword, CalcEngine Plus must have some means of knowing how to find the children of a parent. Once again, this is done by means of an interface, which you must build and pass into the Parser constructor.

The hierarchy-support interfaces

There are actually two different interfaces for supporting hierarchical data. You only have to support one of them. Both interfaces take care of serving sub-expressions too. So you don’t have to implement a hierarchy interface as well as ISubExpressionService - you implement a hierarchy interface instead of ISubExpressionService.

The two interfaces are:

IHierarchySubExpressionService– the simpler interface to work with. This interface extends ISubExpressionService so there’s only one extra method to implement (GetChildTagnames). However this one won’t work if your hierarchy contains duplicated tagnames.


   List GetChildTagnames(string parentTagname);

IContextualSubExpressionService - the more demanding interface. There are three methods to implement; one for for sub-expression resolution, one for getting child entities, and a third for resolving a tagname into a unique ID. You must use this interface if your hierarchy contains duplicated tagnames. In such a case, your tagnames must be uniquely identified by some kind of unique key.


   string GetSubExpression(object uniqueParentId, string tagname);
   List GetChildTagEntities(object uniqueId);
   object GetUniqueIdFromTagname(object parentTagId, string tagname);

 

Implementing simple hierarchy support

If your application has entities arranged in a hierarchical structure (or “tree”) and you don’t have duplicate tagnames then your users can use the “children” keyword to create expressions like “sum(children)”. This requires you to implement IHierarchySubExpressionServiceinterface.

As IHierarchySubExpressionService extends ISubExpressionService, your implementation must include the GetSubExpression method. We saw this earlier (link) so we won’t duplicate it here. The other method you must implement is the GetChildTagnames method:


   List GetChildTagnames(string parentTagname);

 

This method returns a list of the child tagnames of the given parent. If there are no children, then it should return null. An implementation of this method might be something like


        public List GetChildTagnames(string parentTagname)
        {
            if (string.IsNullOrEmpty(parentTagname))
            {
                return null;
            }

            var TAGNAME = parentTagname.ToUpper();

            // Query a hard-coded database of hierchical entities.
            // nodeDatabase is a Dictionary<string, SimpleHierarchyNode>
            if (this.nodeDatabase.ContainsKey(TAGNAME)) 
            {
                var parentTagObject = this.nodeDatabase[TAGNAME];

                // Make a list of child tagnames
                var list = parentTagObject.Children.Select(node => node.Name).ToList();
                return list;
            }

            return null;
        }

A full example in context is available “here”.