Harry
Harry

Reputation: 13329

Creating a JSON object from a tabbed tree text file

I have this examle of a text file: (I dont know what you call this, a Tree?)

key1
    subkey1
    subkey2
        choice1
key2
    subkey1
    subkey2

I want it to look like this:

[
    {   
        "text":"key1",
        "children":[
            {   
                "text":"subkey1",
                children:[]
            },
            {
                "text":"subkey2",
                children:[
                    {
                        "text":"choice1",
                        "children":[]
                    }
                ]
            },
        ]
    },
    {   
        "text":"key2",
        "children":[
            {   
                "text":"subkey1",
                children:[]
            },
            {   
                "text":"subkey2",
                children:[]
            },
        ]
    }
]

This is what Im doing, I do not understand how you get the children elements into the parent, and this should be able to go infinitely deep.

import itertools
def r(f, depth, parent, l, children):
    for line in f:
        line = line.rstrip()
        newDepth = sum(1 for i in itertools.takewhile(lambda c: c=='\t', line))
        node = line.strip()
        if parent is not None:
            print parent, children
            children = [{"txt":node, "children":[]}]
            # l.append({"txt":parent, "children":children})
        r(f, newDepth, node, l, children)
json_list = []
r(open("test.txt"), 0, None, json_list, [])
print json_list

Upvotes: 3

Views: 816

Answers (1)

DrV
DrV

Reputation: 23530

First rule, avoid recursion if you can... Here you only need to know the ancestors, and they can be easily maintained in a list. Note that depth 0 is reserved for the root node, and the first "user" depth is 1, hence the +1 when counting the tabs.

f = open("/tmp/test.txt", "r")

depth = 0
root = { "txt": "root", "children": [] }
parents = []
node = root
for line in f:
    line = line.rstrip()
    newDepth = len(line) - len(line.lstrip("\t")) + 1
    print newDepth, line
    # if the new depth is shallower than previous, we need to remove items from the list
    if newDepth < depth:
        parents = parents[:newDepth]
    # if the new depth is deeper, we need to add our previous node
    elif newDepth == depth + 1:
        parents.append(node)
    # levels skipped, not possible
    elif newDepth > depth + 1:
        raise Exception("Invalid file")
    depth = newDepth

    # create the new node
    node = {"txt": line.strip(), "children":[]}
    # add the new node into its parent's children
    parents[-1]["children"].append(node)

json_list = root["children"]
print json_list

Upvotes: 6

Related Questions