public TemplateData asList()
        {
            if (this.type == "list")
            {
                // already a list, so just clone it
                return(new TemplateData(this));
            }
            Dictionary <string, object> dict = (Dictionary <string, object>)JsonSupport.Deserialize(this.toJson());
            List <object> list = new List <object>();

            list.Add(dict);
            return(new TemplateData(list));
        }
        static List <object> foundObjects;        // used to protect against ToJson loops
        public TemplateData(object jsonData, TemplateData parent = null)
        {
            object json;

            if (jsonData is string)
            {
                json = JsonSupport.Deserialize((string)jsonData);
                // TemplateData supports arrays of strings by making them lists of dictionaries with a single element
                ///json = JsonSerializer.Deserialize<dynamic>("{\"_\": \"" + ((string)jsonData).Replace("\"", "\\\"") + "\"}");
            }
            else if (jsonData is List <object> || jsonData is Object[] || jsonData is ArrayList)
            {
                this.type = "list";
                if (jsonData is ArrayList)
                {
                    jsonData = ((ArrayList)jsonData).ToArray().ToList();
                }
                else if (jsonData is Object[])
                {
                    jsonData = ((Object[])jsonData).ToList();
                }
                ((IList <object>)jsonData).ToList().ForEach((item) => {
                    this.list.Add(new TemplateData(item, this));
                });
                this.parent = parent;
                return;
            }
            else if (jsonData is TemplateData)
            {
                // filter or clone
                if (((TemplateData)jsonData).type == "list")
                {
                    this.type = "list";
                    ((TemplateData)jsonData).list.ForEach((item) =>
                    {
                        this.list.Add(new TemplateData(item, parent));
                    });
                    return;
                }
                else
                {
                    json = JsonSupport.Deserialize(((TemplateData)jsonData).toJson());                     // clone by converting to Json and back
                }
            }
            else
            {
                json = jsonData;
            }
            if (json is List <object> )
            {
                this.type = "list";
                ((List <object>)json).ForEach(item =>
                {
                    this.list.Add(new TemplateData(item is TemplateData || item is Dictionary <string, object>?item: item.ToString(), this));
                });
            }
            else
            {
                object converted = JsonSupport.ConvertToDictionaryOrList(json);
                if (converted is Dictionary <string, object> )
                {
                    this.type = "dictionary";
                    Dictionary <string, object> dict = new Dictionary <string, object>();
                    foreach (string key in ((Dictionary <string, object>)converted).Keys)
                    {
                        object keyItem = ((Dictionary <string, object>)converted)[key];
                        if (keyItem is List <object> || keyItem is Dictionary <string, object> || keyItem is Object[] || keyItem is ArrayList)
                        {
                            dict.Add(key, new TemplateData(((Dictionary <string, object>)converted)[key], this));
                        }
                        else
                        {
                            dict.Add(key, ((Dictionary <string, object>)converted)[key]);
                        }
                    }
                    this.dictionary = dict;
                }
                else
                {
                    this.type = "list";
                    foreach (object itm in (List <object>)converted)
                    {
                        this.list.Add(new TemplateData(itm));
                    }
                }
            }
            if (parent != null)
            {
                this.parent = parent;
            }
        }