0

I want to save a tree structure to a text file, I then want to reconstruct the file by reading the text file. It will be used for a file tree that should look something like this:

rootnode
|-dir 1
| |-file 1
| |-file 2
|
|-dir 2
|
|-dir 3
  |-file 3.1
  |
  |-dir 3.1
    |-fileName

This is a traversal that I have:

    Tree.prototype.traversalDF = function(callBack) {

        (function depth(currentNode) {
            for (var i=0, length = currentNode.children.length; i < length; i++) {
                depth(currentNode.children[i]);
            }
            callBack(currentNode);
        })(this._root);
    };

this is how it is called:

tree.traversalDF(function(node){
    console.log(node.parent);
    fs.appendFile(path.join(__dirname, '/testTree.txt'), node+ '\n', 'utf8');
})   

this only saves this '[object, object]' the same number of times there are nodes. But I want the data to be saved.

This is the node and the tree properties:

//Every Node will have these properties
function Node(data) {
    this.data = data;
    this.children = [];
};

function Tree(data) {
    //this creates an instance of a node with data passed
    var node = new Node(data);
    //allows access to the properties of node
    this._root = node;

};

This is the saved data How could it be reconstructed:

{"data":"2.2","children":[]}
{"data":"2.1","children":[]}
{"data":"2","children":[{"data":"2.1","children":[]},{"data":"2.2","children":[]}]}
{"data":"lemons","children":[]}
{"data":"4.1","children":[{"data":"lemons","children":[]}]}
{"data":"lemons2","children":[]}
{"data":"5.11","children":[{"data":"lemons2","children":[]}]}
{"data":"4","children":[{"data":"4.1","children":[{"data":"lemons","children":[]}]},{"data":"5.11","children":[{"data":"lemons2","children":[]}]}]}
{"data":"one","children":[{"data":"2","children":[{"data":"2.1","children":[]},{"data":"2.2","children":[]}]},{"data":"4","children":[{"data":"4.1","children":[{"data":"lemons","children":[]}]},{"data":"5.11","children":[{"data":"lemons2","children":[]}]}]}]}
help please
  • 25
  • 2
  • 11

2 Answers2

2

Use JSON.stringify(node) instead of just node in the traversalDF callback. You actually don't need to traverse it at all; you should be able to just call JSON.stringify(obj) to serialize it.

To deserialize it, just use JSON.parse(/* string */) after reading it from the file.

River Tam
  • 3,096
  • 4
  • 31
  • 51
  • I have tried that before but have recieved this error: 'Converting circular structure to JSON' – help please Jan 15 '18 at 19:15
  • @helpplease in that case, you have a circular structure rather than a tree. You will need to specify what you'd like to do when encountering a repeated reference, as the default would be to just infinitely recurse (obviously not possible in the physical world). Either way, you should not be calling `callBack` on all arguments to `depth`, as this will call `callBack` on both the `currentNode` and all its children, whereas I believe you want to be doing this only on the children. I believe your code should infinitely recurse as you have describe it, though. – River Tam Jan 15 '18 at 19:19
  • 1
    If the circular references are due to properties on each node but not `children` (I see each node has a `parent` property which is likely the culprit), it is possible you simply need to wrap `callBack(currentNode)` in an `if (currentNode.children) { }` block or similar. It would be very helpful to me if you could post an example of a `Tree` object in a JSON-like format. It is likely the solution is not going to be as simple as you'd like it to be. – River Tam Jan 15 '18 at 19:27
  • [This question](https://stackoverflow.com/questions/11616630/json-stringify-avoid-typeerror-converting-circular-structure-to-json) may help you significantly. – River Tam Jan 15 '18 at 19:31
  • I have removed the parent attribute of each node. From this, I am able to save the data to the text file [see edit]. Is this still considered a tree if the node doesn't have parent attribute? I have no idea how to reconstruct this though any hints would be appreciated. – help please Jan 16 '18 at 17:13
  • 1
    Not sure about the proper terminology. If I had to guess, a "tree" is actually necessarily non-cyclical, so nodes with parents are actually *not* trees, technically (though they are, of course, trees conceptually). If I were you, I would simply call `JSON.stringify(...)` on the _whole_ structure rather than individual parts, then `JSON.parse(...)` on the string. Otherwise, you might want to check out lodash.set to see how you might set the property `2.1` on an object. If I get the time later, I may decide to help you reconstruct the tree from what you have, but I think you're working too hard. – River Tam Jan 16 '18 at 19:55
  • 1
    I have been able to reconstruct using the information you have provided, thanks. – help please Jan 17 '18 at 15:22
  • No problem. Glad to help. Your problem is fairly specific, but it would be good for posterity to post your solution either in the question or as an answer. – River Tam Jan 17 '18 at 17:29
0

The tree created is the same as the one desired however the it stores all the data required here is the code:

const fs = require('fs');
const path = require('path');



//Every Node will have these properties
function Node(data) {
    this.data = data;
    this.children = [];
};

function Tree(data) {
    //this creates an instance of a node with data passed
    var node = new Node(data);
    //allows access to the properties of node
    this._root = node;

};

//--------------------------graph traversal code--------------------------------//

Tree.prototype.traversalDF = function(callBack) {

    (function depth(currentNode) {
        for (var i=0, length = currentNode.children.length; i < length; i++) {
            depth(currentNode.children[i]);
        }
        callBack(currentNode);
    })(this._root);
};

Tree.prototype.traversalBF = function(node, pathPart) {
    //determines number of children of the given node

    var length = node.children.length;

    var i = 0;
    var found = false;
    //cycles through until there is a match
    while( found != true && i <= length){
        if(node.children[i] != null){
            if(node.children[i].data == pathPart){
                found = true;
                //when there is a match it returns the node

                return node.children[i];
            }
        } else if( i == length) {
            var nodeFile = new Node(pathPart);

            //adds the file name onto the the node
            node.children.push(nodeFile);
            //sets the node parent to the currentNode
        // nodeFile.parent = node;

            return nodeFile;
        }
        i++;
    }
}

Tree.prototype.add = function(path){
var pathSplit = path.split('/');
//gets the length of the path
var pathLength = pathSplit.length;
//this compares the path to the nodes/directories
let compare = (currentNode, n) => {

    if(n == pathLength -1){

        //create a new node with file name as data
        var nodeFile = new Node(pathSplit[n]);
        //adds the file name onto the the node
        currentNode.children.push(nodeFile);
    }else{
        var newNode = () => this.traversalBF(currentNode, pathSplit[n]);

        compare(newNode(), n+1);
    };

};
compare(this._root, 1);
};


var tree = new Tree('one');

tree.add('one/2/2.1');
tree.add('one/2/2.2');
tree.add('one/hi');
tree.add('one/4/4.1');


tree.add('one/4/4.1/lemons');
tree.add('one/4/5.11/lemons2');

    tree.traversalDF(function(node){
        console.log(node.data);
    });

    //writeFileSyn used instead on appendFile so it overwrites the data in the .txt
    //necessary to use 'writeFileSync' otherwise next line attempts to read an empty file
    fs.writeFileSync(path.join(__dirname, '/testTree.txt'), JSON.stringify(tree) + '\n', 'utf8');
    //reads data from txt file
    var treeRecon = JSON.parse(fs.readFileSync(path.join(__dirname, '/testTree.txt')));
    //creates a tree
    var Reconstructed = new Tree(treeRecon._root.data);
    console.log(Reconstructed);

    for (i = 0; i < treeRecon._root.children.length; i++) {
        //for each child in the root in the children of the root.
        //the children are pushed onto the roots children hence recreating it.
        Reconstructed._root.children.push(treeRecon._root.children[i]);
    }
    console.log(Reconstructed);

    Reconstructed.traversalDF(function(node){
        console.log(node.data);

    });
help please
  • 25
  • 2
  • 11