public string GetTreeAsText(ValueNode dataNode, string levelSep, DataTreeControl control, int levelLimit)
        {
            StringBuilder sb = new StringBuilder();

            // ensure expanded
            control.ListChildItems(dataNode);

            // add children nodes
            GetTreeItemsAsText(new List<Node> { dataNode }, new HashSet<string>(), levelSep, 0, sb, control, levelLimit);

            return sb.ToString();
        }
        private void GetTreeItemsAsText(IList<Node> dataNodes, HashSet<string> visited, string levelSep, int level, StringBuilder sb, DataTreeControl control, int levelLimit)
        {
            // per node
            int len = dataNodes.Count;
            for (int c = 0; c < len; c++)
            {
                ValueNode child = (ValueNode)dataNodes[c];

                // skip if unwanted item
                if (!IsWantedChild(child))
                {
                    continue;
                }

                // ensure expanded
                if (!child.IsLeaf)
                {
                    control.ListChildItems(child);
                }

                // add node
                AppendTimes(sb, levelSep, level);

                // stop recursion if too long
                if (sb.Length > CopyTreeMaxChars)
                {
                    sb.AppendLine("......");
                    return;
                }

                if (child.IsPrimitive)
                {
                    sb.Append(child.Text + " : " + child.Value + " ");
                }
                else
                {
                    sb.Append(child.Text + " : " + child.ClassPath + " ");
                }

                // recurse for children .. but skip if unwanted items
                if (child.Nodes.Count > 0 && IsWantedParent(child))
                {

                    // opening brace
                    sb.AppendLine("{");

                    string childId = child.Id;

                    // add error if too many levels of recursion
                    if (level <= levelLimit || levelLimit == 0)
                    {

                        // check if encountered before
                        bool isNew = childId == "" || !visited.Contains(childId);
                        if (!isNew)
                        {
                            // error
                            AppendTimes(sb, levelSep, level + 1);
                            sb.AppendLine(String.Format(TextHelper.GetString("TreeExporter.DuplicatedObject"), child.Value));
                        }
                        else if (level > CopyTreeMaxRecursion)
                        {
                            // error
                            AppendTimes(sb, levelSep, level + 1);
                            sb.AppendLine(TextHelper.GetString("TreeExporter.MaxDepthReached"));
                        }
                        else
                        {
                            // add to list
                            if (childId != "")
                                visited.Add(childId);

                            // children
                            try
                            {
                                GetTreeItemsAsText(child.Nodes, visited, levelSep, level + 1, sb, control, levelLimit);
                            }
                            catch (Exception) { }
                        }
                    }

                    // closing brace
                    AppendTimes(sb, levelSep, level);
                    sb.AppendLine("}");
                }
                else
                {
                    sb.AppendLine();
                }

            }
        }