如何使用多个最小化级别漂亮地打印 JSON?

How do I pretty print JSON with multiple levels of minimization?

我们有标准的漂亮印刷品JSON:

{
  "results": {
    "groups": {
      "alpha": {
        "items": {
          "apple": {
            "attributes": {
              "class": "fruit"
            }
          },
          "pear": {
            "attributes": {
              "class": "fruit"
            }
          },
          "dog": {
            "attributes": {
              "class": null
            }
          }
        }
      },
      "beta": {
        "items": {
          "banana": {
            "attributes": {
              "class": "fruit"
            }
          }
        }
      }
    }
  }
}

我们有 JMin:

{"results":{"groups":{"alpha":{"items":{"apple":{"attributes":{"class":"fruit"}},"pear":{"attributes":{"class":"fruit"}},"dog":{"attributes":{"class":null}}}},"beta":{"items":{"banana":{"attributes":{"class":"fruit"}}}}}}}

但我希望能够像这样即时打印 JSON:

{
  "results" : {
    "groups" : {
      "alpha" : {
        "items" : {
          "apple":{"attributes":{"class":"fruit"}},
          "pear":{"attributes":{"class":"fruit"}},
          "dog":{"attributes":{"class":null}}
        }
      },
      "beta" : {
        "items" : {
          "banana":{"attributes":{"class":"fruit"}}}
      }
    }
  }
}

以上我会描述为"pretty-print JSON, minimized at level 5"。有没有工具可以做到这一点?

我写了自己的 JSON 格式化程序,基于 this script:

#! /usr/bin/env python
VERSION = "1.0.1"

import sys
import json
from optparse import OptionParser

def to_json(o, level=0):
    if level < FOLD_LEVEL:
        newline = "\n"
        space = " "
    else:
        newline = ""
        space = ""
    ret = ""
    if isinstance(o, basestring):
        o = o.encode('unicode_escape')
        ret += '"' + o + '"'
    elif isinstance(o, bool):
        ret += "true" if o else "false"
    elif isinstance(o, float):
        ret += '%.7g' % o
    elif isinstance(o, int):
        ret += str(o)
    elif isinstance(o, list):
        #ret += "[" + ",".join([to_json(e, level+1) for e in o]) + "]"
        ret += "[" + newline
        comma = ""
        for e in o:
            ret += comma
            comma = "," + newline
            ret += space * INDENT * (level+1)
            ret += to_json(e, level+1)
        ret += newline + space * INDENT * level + "]"
    elif isinstance(o, dict):
        ret += "{" + newline
        comma = ""
        for k,v in o.iteritems():
            ret += comma
            comma = "," + newline
            ret += space * INDENT * (level+1)
            #ret += '"' + str(k) + '"' + space + ':' + space
            ret += '"' + str(k) + '":' + space
            ret += to_json(v, level+1)
        ret += newline + space * INDENT * level + "}"
    elif o is None:
        ret += "null"
    else:
        #raise TypeError("Unknown type '%s' for json serialization" % str(type(o)))
        ret += str(o)
    return ret


#main():
FOLD_LEVEL = 10000
INDENT = 4

parser = OptionParser(usage='%prog json_file [options]', version=VERSION)
parser.add_option("-f", "--fold-level", action="store", type="int",
          dest="fold_level", help="int (all json is minimized to this level)")
parser.add_option("-i", "--indent", action="store", type="int",
          dest="indent", help="int (spaces of indentation, default is 4)")
parser.add_option("-o", "--outfile", action="store", type="string",
          dest="outfile", metavar="filename", help="write output to a file")
(options, args) = parser.parse_args()

if len(args) == 0:
    infile = sys.stdin
elif len(args) == 1:
    infile = open(args[0], 'rb')
else:
    raise SystemExit(sys.argv[0] + " json_file [options]")
if options.outfile == None:
    outfile = sys.stdout
else:
    outfile = open(options.outfile, 'wb')
if options.fold_level != None:
    FOLD_LEVEL = options.fold_level
if options.indent != None:
    INDENT = options.indent

with infile:
    try:
        obj = json.load(infile)
    except ValueError, e:
        raise SystemExit(e)
with outfile:
    outfile.write(to_json(obj))
    outfile.write('\n')

脚本从命令行接受折叠级别、缩进和输出文件:

$ jsonfold.py -h
Usage: jsonfold.py json_file [options]

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -f FOLD_LEVEL, --fold-level=FOLD_LEVEL
                        int (all json is minimized to this level)
  -i INDENT, --indent=INDENT
                        int (spaces of indentation, default is 4)
  -o filename, --outfile=filename
                        write output to a file

从上面的示例中,在第 5 级弃牌:

$ jsonfold.py test2 -f 5
{
    "results": {
        "groups": {
            "alpha": {
                "items": {
                    "pear": {"attributes":{"class":"fruit"}},
                    "apple": {"attributes":{"class":"fruit"}},
                    "dog": {"attributes":{"class":None}}
                }
            },
            "beta": {
                "items": {
                    "banana": {"attributes":{"class":"fruit"}}
                }
            }
        }
    }
}