using System.Collections.Generic;
public static void Main()
var testString = "At First Level|1 - At First Level| 2 - Child of 1| 3 - Child of 1| 4 - Child of 3| 5 - Child of 1|last - At First Level";
var rdo = RelatedDataObject.CreateFrom(testString);
var jsonString = JsonConvert.SerializeObject(rdo, Formatting.Indented);
Console.WriteLine(jsonString);
public class RelatedDataObject
public string Record { get; set; }
public IEnumerable<RelatedDataObject> SubRecords { get; set; }
private class ParentChildId
public string Value { get; set; }
public int Parent { get; set; }
public int Id { get; set; }
public static IEnumerable<RelatedDataObject> CreateFrom(string value)
var list = new List<RelatedDataObject>();
if (string.IsNullOrWhiteSpace(value))
if (!value.Contains("|"))
list.Add(new RelatedDataObject { Record = value });
var items = new List<ParentChildId>();
var depthList = new Stack<KeyValuePair<int, int>>();
depthList.Push(new KeyValuePair<int, int>(0, -1));
foreach (var item in value.Split('|'))
var currentIndentation = item.TakeWhile(Char.IsWhiteSpace).Count() / 5;
var depthItem = depthList.Pop();
if (currentIndentation == 0)
depthList = new Stack<KeyValuePair<int, int>>();
depthList.Push(new KeyValuePair<int, int>(0, -1));
depthList.Push(new KeyValuePair<int, int>(currentIndentation, index));
else if (depthItem.Key == currentIndentation)
parent = depthList.Peek().Value;
depthList.Push(new KeyValuePair<int, int>(currentIndentation, index));
else if (depthItem.Key > currentIndentation)
while (depthItem.Key > currentIndentation)
depthItem = depthList.Pop();
parent = depthList.Peek().Value;
else if (depthItem.Key < currentIndentation)
parent = depthItem.Value;
depthList.Push(depthItem);
depthList.Push(new KeyValuePair<int, int>(currentIndentation, index));
items.Add(new ParentChildId { Value = item.Trim(), Parent = parent, Id = index++ });
foreach (var item in items.Where(t => t.Parent == -1))
list.Add(new RelatedDataObject { Record = item.Value, SubRecords = GetChildren(items, item.Id) });
private static IEnumerable<RelatedDataObject> GetChildren(IEnumerable<ParentChildId> records, int parentId)
if (!records.Any(t => t.Parent == parentId))
var childRecords = records.Where(t => t.Parent == parentId);
var recs = childRecords.Select(t => new RelatedDataObject { Record = t.Value, SubRecords = GetChildren(records, t.Id) });