9

I've looked around for an answer, but I think this is a kind of weird question. How would I convert, as a text file using tabs for spacing, this:

parent
    child
    child
parent
    child
        grandchild
        grandhcild

to

{
"name" : "parent",
"children" : [
    {"name" : "child"},
    {"name" : "child"},
]
},
{
"name" : "parent",
"children" : [
    {
    "name" : "child",
    "children" : [
        {"name" : "grandchild"},
        {"name" : "grandchild"},
        {"name" : "grandchild"},
    ]
    },
]
}

JSON probably isn't perfect, but hopefully makes my point clear.

1
  • 1
    Have you tried anything yourself? Commented Jan 9, 2014 at 21:37

4 Answers 4

7

i've had the same problem. Here is the solution:

function node(title,lvl){
    var children = [],
        parent = null;
    return {
        title:title,
        children:children,
        lvl:()=>lvl==undefined?-1:lvl,
        parent:()=>parent, //as a function to prevent circular reference when parse to JSON
        setParent:p=>{parent=p},
        appendChildren: function(c){
            children.push(c); 
            c.setParent(this);
            return this
        },
    }
}
function append_rec(prev,curr) {
    if(typeof(curr)=='string'){ //in the recursive call it's a object
        curr = curr.split('    ');//or tab (\t)
        curr = node(curr.pop(),curr.length);
    }
    if(curr.lvl()>prev.lvl()){//curr is prev's child
        prev.appendChildren(curr);
    }else if(curr.lvl()<prev.lvl()){
        append_rec(prev.parent(),curr) //recursive call to find the right parent level
    }else{//curr is prev's sibling
        prev.parent().appendChildren(curr);
    }

    return curr;
}

root = node('root');

var txt = 
`parent
    child
    child
parent
    child
        grandchild
        grandhcild`;
        
txt.toString().split('\n').reduce(append_rec,root); 

console.log(JSON.stringify(root.children,null,3));

Sign up to request clarification or add additional context in comments.

Comments

3

I've just implemented this feature for the tabdown markup language — it does exactly what you sought for. https://github.com/antyakushev/tabdown

Usage is pretty simple:

var lines = data.toString().split('\n');
var tree = tabdown.parse(lines);
console.log(tree.toString());

You can also use the parse function outside of node.js, it does not depend on any modules.

2 Comments

Oh, it's just a less verbose way to print out the same data. However, the tree structure itself does contain properties "data" and "children" (for "name" and "children" in the example respectively), therefore it can be used as a js object in the desired format.
This looks like a good solution, but tabdown is not available on npm.
0

This is my regex-based, recursion-free approach. It looks a bit "hacky" but makes perfect sense, you can try each step on regexr if you want to. It's written purposely verbose and can probably be compressed a bit. Also, this code assumes your text is tab-indented and only has one "parent", but you should be able to easily replace your indents and add a single "root" parent beforehand.

const string = `
parent
    child
        grandchild
    child
    child
        grandchild
        grandchild
`;



let json = string
  .replace(
    /(?:(\t+)(\S+)(?=(?:\n(?:(?:(?!\1))|(?:\1\S)))|$))/g,
    "$1{\n$1\t\"name\": \"$2\",\n$1\t\"children\": []\n$1},"
  ) // this one replaces all empty nodes with a simple object with an empty children array
  .replace(
    /(?<=(^\t*))([^\s{]+)$\n(?=\1\t)/gm,
    "{\"name\": \"$2\",\"children\": [\n"
  ); // this one replaces every immediate parent with an object and a starting children array

const lines = string.split("\n");

const maxDepth = Math.max(
  ...lines.map(line => line.replace(/[^\t]/g, "").length)
);

// this one basically closes all square brackets and curly braces
// this is a loop because it depends on the max depth of your source text and i also don't like recursion
for (let index = 0; index < maxDepth - 1; index++) {
  json = json.replace(
    /(^\t+)(.*,)("children": \[)((\n\1\t+[^\t\n]+)+)/gm,
    "$1$2\n$1$3$4\n$1]},"
  )
}

// this closes the root object brackets and removes trailing commas and newlines
json = `${json}\n]}`.replace(/,(?=\s*\])/g, "").replace(/\n/g, "");

const object = JSON.parse(json);

const betterLookingJson = JSON.stringify(object, null, "\t");

console.log(object);
console.log(betterLookingJson);

Comments

-2

Generate JSON from Tab Tree Text File

The links below attack your problem specifically. All you need to do is update the code so the output is formatted to your requirements.


Tab Delimiter to JSON

Other Help

2 Comments

To clarify, this doesn't really have anything to do with a CSV or TSV file. Tabs are used purely to show the generational level in the tree. If a line is indented once, it's in the second generation. No tabs means it's first-generation, and two tabs is third-generation.
@user1114864 The links I added address your problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.