isaksham isaksham - 6 months ago 11
JSON Question

Node JS: Make a flat json from a tree json

I was writing a node.js script to combine all the json files in a directory and store the result as a new json file. I tried do the job to a great extent but it has few flaws.

A.json


[
{
"id": "addEmoticon1",
"description": "Message to greet the user.",
"defaultMessage": "Hello, {name}!"
},
{
"id": "addPhoto1",
"description": "How are youu.",
"defaultMessage": "How are you??"
}
]


B.json


[
{
"id": "close1",
"description": "Close it.",
"defaultMessage": "Close!"
}
]


What I finally need is:

result.json


{
"addEmoticon1": "Hello, {name}!",
"addPhoto1": "How are you??",
"close1": "Close!"
}


I wrote a node.js script:

var fs = require('fs');

function readFiles(dirname, onFileContent, onError) {
fs.readdir(dirname, function(err, filenames) {
if (err) {
onError(err);
return;
}
filenames.forEach(function(filename) {
fs.readFile(dirname + filename, 'utf-8', function(err, content) {
if (err) {
onError(err);
return;
}
onFileContent(filename, content);
});
});
});
}

var data = {};
readFiles('C:/node/test/', function(filename, content) {
data[filename] = content;
var lines = content.split('\n');
lines.forEach(function(line) {
var parts = line.split('"');
if (parts[1] == 'id') {
fs.appendFile('result.json', parts[3]+': ', function (err) {});
}
if (parts[1] == 'defaultMessage') {
fs.appendFile('result.json', parts[3]+',\n', function (err) {});
}
});
}, function(err) {
throw err;
});


It extracts the 'id' and 'defaultMessage' but is not able to append correctly.

What I get:

result.json


addEmoticon1: addPhoto1: Hello, {name}!,
close1: How are you??,
Close!,


This output is different every time I run my script.


  • Aim 1: Surround items in double quotes,

  • Aim 2: Add curly braces at the top and at the end

  • Aim 3: No comma at the end of last element

  • Aim 4: Same output every time I run my script


Answer

Here's my solution:

function readFiles(dirname, onFileContent, onError) {

    fs.readdir(dirname, function(err, filenames) {

        /**
         * We'll store the parsed JSON data in this array
         * @type {Array}
         */
        var fileContent = [];

        if (err) {
            onError(err);
        } else {

            filenames.forEach(function(filename) {

                // Reading the file (synchronously) and storing the parsed JSON output (parsing from string to JSON object)
                var jsonObject = JSON.parse(fs.readFileSync(dirname + filename, 'utf-8'));

                // Pushing the parsed JSON output into array
                fileContent.push(jsonObject);
            });

            // Calling the callback
            onFileContent(fileContent);
        }
    });
}

readFiles('./files/',function(fileContent) {

    /**
     * We'll store the final output object here
     * @type {Object}
     */
    var output = {};

    // Loop over the JSON objects
    fileContent.forEach(function(each) {

        // Looping within each object
        for (var index in each) {

            // Copying the `id` as key and the `defaultMessage` as value and storing in output object
            output[each[index].id] = each[index].defaultMessage;
        }
    });

    // Writing the file (synchronously) after converting the JSON object back to string
    fs.writeFileSync('result.json', JSON.stringify(output));

}, function(err) {

    throw err;
});

Notable difference is that I've not used the asynchronous readFile and writeFile functions as they'd needlessly complicate the example. This example is meant to showcase the use of JSON.parse and JSON.stringify to do what OP wants.

Comments