I'd like to be able to parse a string into a JSON Object, something like this (the text can be anything, I'm just putting them like this so you can see the structure):
A
A-A
A-B
A-B-A
A-B-B
A-C
A-C-A
B
into a json object, structured like this:
[
{
"root": "A",
"content": [
{ "root": "A-A", "content": [] },
{
"root": "A-B",
"content": [
{ "root": "A-B-A", "content": [] },
{ "root": "A-B-B", "content": [] }
]
},
{
"root": "A-C",
"content": [
{ "root": "A-C-A", "content": [] }
]
}
]
},
{ "root": "B", "content": [] }
]
So far, I have the following, but I'm not sure if this is the best way of doing it. Maybe a recursive approach would be better?
let body = [];
let indentStack = [0];
for (let line of input.split('\n')) { // input is the string I'd like to parse
if (line.trim() == '') continue; // skips over empty lines
let indent = line.match(/^ +/);
indent = indent ? indent[0].length : 0; // matches the first group of spaces with regex, gets the indent level of this line
if (indentStack[indentStack.length-1] != indent)
if (indentStack.includes(indent)) indentStack.length = indentStack.indexOf(indent)+1; // remove all indent levels after it as it's returned back to a higher level
else stack.push(indent);
console.log(`${(indent + '[' + indentStack.join() + ']').padEnd(10, ' ')}: ${line}`); // debugging
if (indentStack.length == 1) body.push({ root: line, content: [] });
else {
body[body.length-1].content.push({ root: line.substring(indent), content: [] })
}
}
console.log(body)
I will do that this way :
const data =
`A
A-A
A-B
A-B-A
A-B-B
A-C
A-C-A
B`;
function doTree(data)
{
let
res = []
, levels = [ res ]
;
for (let line of data.split('\n'))
{
let
level = line.search(/\S/) >> 1 // (index of first non whitespace char) / 2 --> IF indentation is 2 spaces
, root = line.trim()
, content = []
;
if (!root) continue
levels[level].push({root,content})
levels[++level] = content
}
return res
}
console.log( doTree(data) )
.as-console-wrapper {max-height: 100%!important;top:0 }
The question about indentations ...
here you can have unequal indentation steps,
either with spaces or with tabs.
(do not mix spaces and tabs)
const data_023c = // indentation values are 0c, 2c, 3c
`A
A-A
A-B
A-B-A
A-B-B
A-C
A-C-A
B`;
const indentation= (()=> // IIFE
{
let
indents = []
, max = -1
;
return {
clear:() =>
{
indents.length = 0
max = -1
}
, get:(line, lNum='?' ) =>
{
let ncBefore = line.search(/\S/)
let level = indents.indexOf(ncBefore)
if (level===-1)
{
if (ncBefore < max) throw `error on indentation,\n line = ${lNum},\n line value is = "${line}"`
level = indents.push( ncBefore) -1
max = ncBefore
}
return level
}
}
})()
const doTree = data =>
{
let
res = []
, levels = [ res ]
, lineN = 0
;
indentation.clear()
for (let line of data.split('\n'))
{
lineN++ // line counter for indent error message
let
root = line.trim()
, content = []
;
if (!root) continue
let level = indentation.get(line, lineN)
levels[level].push({root,content})
levels[++level] = content
}
return res
}
console.log( doTree(data_023c) )
.as-console-wrapper {max-height: 100%!important;top:0 }