diff options
author | Russ Cox <rsc@golang.org> | 2010-04-18 14:45:08 -0700 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2010-04-18 14:45:08 -0700 |
commit | 8e87e685b81a225e533d1269c972bd0131971454 (patch) | |
tree | 84ba9f13642d56d90ace3d90f69e6b366cbef490 /src/pkg/json/indent.go | |
parent | 910aad8711d5bfaf09cf75f4eb5cce2b931d8105 (diff) | |
download | golang-8e87e685b81a225e533d1269c972bd0131971454.tar.gz |
json: scanner, Compact, Indent, and tests
This is the first of probably four separate CLs
for the new implementation of the json package.
The scanner is the core of the new implementation.
The other CLs would be the new decoder,
the new encoder, and support for JSON streams.
R=r
CC=golang-dev
http://codereview.appspot.com/802051
Diffstat (limited to 'src/pkg/json/indent.go')
-rw-r--r-- | src/pkg/json/indent.go | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/src/pkg/json/indent.go b/src/pkg/json/indent.go new file mode 100644 index 000000000..000da42f6 --- /dev/null +++ b/src/pkg/json/indent.go @@ -0,0 +1,116 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package json + +import ( + "bytes" + "os" +) + +// Compact appends to dst the JSON-encoded src with +// insignificant space characters elided. +func Compact(dst *bytes.Buffer, src []byte) os.Error { + origLen := dst.Len() + var scan scanner + scan.reset() + start := 0 + for i, c := range src { + v := scan.step(&scan, int(c)) + if v >= scanSkipSpace { + if v == scanError { + break + } + if start < i { + dst.Write(src[start:i]) + } + start = i + 1 + } + } + if scan.eof() == scanError { + dst.Truncate(origLen) + return scan.err + } + if start < len(src) { + dst.Write(src[start:]) + } + return nil +} + +func newline(dst *bytes.Buffer, prefix, indent string, depth int) { + dst.WriteByte('\n') + dst.WriteString(prefix) + for i := 0; i < depth; i++ { + dst.WriteString(indent) + } +} + +// Indent appends to dst an indented form of the JSON-encoded src. +// Each element in a JSON object or array begins on a new, +// indented line beginning with prefix followed by one or more +// copies of indent according to the indentation nesting. +// The data appended to dst has no trailing newline, to make it easier +// to embed inside other formatted JSON data. +func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) os.Error { + origLen := dst.Len() + var scan scanner + scan.reset() + needIndent := false + depth := 0 + for _, c := range src { + v := scan.step(&scan, int(c)) + if v == scanSkipSpace { + continue + } + if v == scanError { + break + } + if needIndent && v != scanEndObject && v != scanEndArray { + needIndent = false + depth++ + newline(dst, prefix, indent, depth) + } + + // Emit semantically uninteresting bytes + // (in particular, punctuation in strings) unmodified. + if v == scanContinue { + dst.WriteByte(c) + continue + } + + // Add spacing around real punctuation. + switch c { + case '{', '[': + // delay indent so that empty object and array are formatted as {} and []. + needIndent = true + dst.WriteByte(c) + + case ',': + dst.WriteByte(c) + newline(dst, prefix, indent, depth) + + case ':': + dst.WriteByte(c) + dst.WriteByte(' ') + + case '}', ']': + if needIndent { + // suppress indent in empty object/array + needIndent = false + } else { + depth-- + newline(dst, prefix, indent, depth) + } + dst.WriteByte(c) + + default: + dst.WriteByte(c) + } + } + if scan.eof() == scanError { + dst.Truncate(origLen) + return scan.err + } + return nil +} |