将JSON对象格式化输出(上篇)

UPDATE:经公子大大提醒,使用JSON API就可以做到下面的效果。

(这后面的内容不用看了) 最近在使用Node.js开发项目,由于JavaScript内置了对JSON的支持,自然而然想到了使用JSON编写配置文件。

// app.json
{"mode": "prod", "log_path": "/data"}; //还有更多内容
var app = require('./app.json');
var fs = require('fs');
// 某些操作,保存app
fs.writeFile('/path/to/app.json', JSON.stringify(app),
    function(err) {
        if(err) throw err;
    });

如果配置文件比较复杂时,就需要分多行添加缩进等重新排版,但是只要程序读写保存过一次后,原来辛辛苦苦排版好的JSON文件内容又扎堆在一起了。对于开发人员来说或许不那么头疼,但对于运维人员(我司运维工程师们)却不是这样的,为了方便他们及我们读写修改JSON配置文件,于是就在网上搜索类json pretty tools的Node.js模块,便找到了prettyjson这个模块,不过这个模块时将对象输出成YAML风格,不太符合我的需求。 省略中间的过程。 修改后的代码:

'use strict';

// ### Render function
// *Parameters:*
//
// * **`data`**: Data to render
// * **`options`**: Hash with different options to configure the parser
// * **`indentation`**: Base indentation of the parsed output
//
// *Example of options hash:*
//
//     {
//       defaultIndentation: 2     // Indentation on nested objects
//     }
exports.render = function render(data, options, indentation) {
  // Default values
  indentation = indentation || 0;
  options = options || {};
  options.defaultIndentation = options.defaultIndentation || 2;

  var output = [];

  // Helper function to detect if an object can be directly serializable
  var isSerializable = function(input, onlyPrimitives) {
    if (typeof input === 'boolean' ||
        typeof input === 'number' || input === null) {
      return true;
    }
    if (typeof input === 'string' && input.indexOf('\n') === -1) {
      return true;
    }

    return false;
  };

  var indentLines = function(string, spaces){
    var lines = string.split('\n');
    lines = lines.map(function(line){
      return indent(spaces) + line;
    });
    return lines.join('\n');
  };

  var outputData = function(input) {

    if (typeof input === 'string') {
      // Print strings wraped by double quote
      return '"' + input + '"';
    }

    if (input === true) {
      return 'true';
    }
    if (input === false) {
      return 'false';
    }
    if (input === null) {
      return '';
    }
    if (typeof input === 'number') {
      return input;
    }

    return input;
  };
  var removeLastComma = function(output) {
      var lastElement = output[output.length-1];
      output[output.length-1] = lastElement.substr(0, lastElement.length-1);
  };
  var indent = function(numSpaces) {
    return new Array(numSpaces+1).join(' ');
  };
  // Render a string exactly equal
  if (isSerializable(data)) {
    output.push(indent(indentation) + outputData(data));
  }
  else if (typeof data === 'string') {
    var lines = data.split('\n');
    lines.map(function(line){
      return indent(indentation + options.defaultIndentation) + '"' + line + '"';
    });
    output.push(lines.join(',\n'));
  }
  else if (Array.isArray(data)) {
    var line = indent(indentation);
    indentation = indentation + options.defaultIndentation;
    output.push(line + '[');
    // If the array is empty
    if (data.length === 0) {
      output.push(indent(indentation) +' ');
    } else {
      data.forEach(function(element) {
        if(isSerializable(element)) {
            output.push(indent(indentation) + outputData(element) + ',');
        }else {
            output.push(exports.render(element, options, indentation) + ',');
        }
      });
      removeLastComma(output);
    }
    output.push(line + '],');
  }
  else if (typeof data === 'object') {
    var line = indent(indentation);
    output.push(line+'{');
    var key;
    var isError = data instanceof Error;
    indentation = indentation + options.defaultIndentation;
    Object.getOwnPropertyNames(data).forEach(function(i) {
      // Prepend the index at the beginning of the line
      key = ('"' + i +'"'+ ': ');
      key = indent(indentation) + key;

      // Skip `undefined`, it's not a valid JSON value.
      if (data[i] === undefined) {
        return;
      }
      if(isSerializable(data[i])) {
        output.push(key + outputData(data[i]) + ',');
      }else {
        var temp = exports.render(data[i], options, indentation);
        output.push(key + temp.trim() + ',');
      }
    });
    removeLastComma(output);
    output.push(line + '},');
  }
  removeLastComma(output);
  // Return all the lines as a string
  return output.join('\n');
};

// ### Render from string function
// *Parameters:*
//
// * **`data`**: Data to render as a string
// * **`options`**: Hash with different options to configure the parser
// * **`indentation`**: Base indentation of the parsed output
//
// *Example of options hash:*
//
//     {
//       defaultIndentation: 2     // Indentation on nested objects
//     }
exports.renderString = function renderString(data, options, indentation) {

  var output = '';
  var parsedData;
  // If the input is not a string or if it's empty, just return an empty string
  if (typeof data !== 'string' || data === '') {
    return '';
  }

  // Remove non-JSON characters from the beginning string
  if (data[0] !== '{' && data[0] !== '[') {
    var beginingOfJson;
    if (data.indexOf('{') === -1) {
      beginingOfJson = data.indexOf('[');
    } else if (data.indexOf('[') === -1) {
      beginingOfJson = data.indexOf('{');
    } else if (data.indexOf('{') < data.indexOf('[')) {
      beginingOfJson = data.indexOf('{');
    } else {
      beginingOfJson = data.indexOf('[');
    }
    output += data.substr(0, beginingOfJson) + '\n';
    data = data.substr(beginingOfJson);
  }

  try {
    parsedData = JSON.parse(data);
  } catch (e) {
    // Return an error in case of an invalid JSON
    return 'Error:' + ' Not valid JSON!';
  }

  // Call the real render() method
  output += exports.render(parsedData, options, indentation);
  return output;
};

这样之后原来程序代码基本不变,在保存对象到JSON文件时做了调整:

+var prettyjson = require('./lib/prettyjson');
-fs.writeFile('/path/to/app.json', JSON.stringify(app),
+fs.writeFile('/path/to/app.json', prettyjson.render(app),
    function(err) {
        if(err) throw err;
    });

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一个会写诗的程序员的博客

正则表达式 删除 Java 代码中的注释

想如何删掉所有java 或xml 中的注释,还在寻找eclipse 中的快捷键了吗,你out了,现在都用正则表达式了、

22940
来自专栏大前端_Web

深入理解JS异步编程(一)

版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://blog.csdn.net/wkyseo/articl...

46650
来自专栏Youngxj

Chrome控制台console的基本用法

21650
来自专栏JAVA技术站

linux学习之sed 转

sed是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换、删除、新增、选取等特定工作,下面先了解一下sed的用法 s...

9520
来自专栏蓝天

小心两个共享库共用同一个静态库

小心两个共享库共用同一个静态库.pdf 注:以下内容仅针对Linux/GCC环境,不涵盖Windows,包括Cygwin环境。 下载测试代码:

16650
来自专栏猛牛哥的博客

aardio v13.7 更新内容

16230
来自专栏大数据挖掘DT机器学习

Python Excel操作

最近公司要把Excel导入到mysql数据库,查了几篇博文,这几项是非常有用的,记录下来。 一、安装xlrd模块 到python官网下载http://pyp...

39840
来自专栏前端架构

再谈angularJS数据绑定机制及背后原理—angularJS常见问题总结

ng-bind 单向数据绑定($scope -> view),用于数据显示,简写形式是 {{}}。

20230
来自专栏优启梦

Chrome控制台console的基本用法

大家都有用过各种类型的浏览器,每种浏览器都有自己的特色,本人拙见,在我用过的浏览器当中,我是最喜欢Chrome的,因为它对于调试脚本及前端设计调试都有它比其它浏...

467120
来自专栏python全栈布道师

使用python读取和写入Excel

43760

扫码关注云+社区

领取腾讯云代金券