The Go Programming Language

Source file src/pkg/json/indent.go

     1	// Copyright 2010 The Go Authors.  All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	package json
     6	
     7	import (
     8		"bytes"
     9		"os"
    10	)
    11	
    12	// Compact appends to dst the JSON-encoded src with
    13	// insignificant space characters elided.
    14	func Compact(dst *bytes.Buffer, src []byte) os.Error {
    15		origLen := dst.Len()
    16		var scan scanner
    17		scan.reset()
    18		start := 0
    19		for i, c := range src {
    20			v := scan.step(&scan, int(c))
    21			if v >= scanSkipSpace {
    22				if v == scanError {
    23					break
    24				}
    25				if start < i {
    26					dst.Write(src[start:i])
    27				}
    28				start = i + 1
    29			}
    30		}
    31		if scan.eof() == scanError {
    32			dst.Truncate(origLen)
    33			return scan.err
    34		}
    35		if start < len(src) {
    36			dst.Write(src[start:])
    37		}
    38		return nil
    39	}
    40	
    41	func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
    42		dst.WriteByte('\n')
    43		dst.WriteString(prefix)
    44		for i := 0; i < depth; i++ {
    45			dst.WriteString(indent)
    46		}
    47	}
    48	
    49	// Indent appends to dst an indented form of the JSON-encoded src.
    50	// Each element in a JSON object or array begins on a new,
    51	// indented line beginning with prefix followed by one or more
    52	// copies of indent according to the indentation nesting.
    53	// The data appended to dst has no trailing newline, to make it easier
    54	// to embed inside other formatted JSON data.
    55	func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) os.Error {
    56		origLen := dst.Len()
    57		var scan scanner
    58		scan.reset()
    59		needIndent := false
    60		depth := 0
    61		for _, c := range src {
    62			v := scan.step(&scan, int(c))
    63			if v == scanSkipSpace {
    64				continue
    65			}
    66			if v == scanError {
    67				break
    68			}
    69			if needIndent && v != scanEndObject && v != scanEndArray {
    70				needIndent = false
    71				depth++
    72				newline(dst, prefix, indent, depth)
    73			}
    74	
    75			// Emit semantically uninteresting bytes
    76			// (in particular, punctuation in strings) unmodified.
    77			if v == scanContinue {
    78				dst.WriteByte(c)
    79				continue
    80			}
    81	
    82			// Add spacing around real punctuation.
    83			switch c {
    84			case '{', '[':
    85				// delay indent so that empty object and array are formatted as {} and [].
    86				needIndent = true
    87				dst.WriteByte(c)
    88	
    89			case ',':
    90				dst.WriteByte(c)
    91				newline(dst, prefix, indent, depth)
    92	
    93			case ':':
    94				dst.WriteByte(c)
    95				dst.WriteByte(' ')
    96	
    97			case '}', ']':
    98				if needIndent {
    99					// suppress indent in empty object/array
   100					needIndent = false
   101				} else {
   102					depth--
   103					newline(dst, prefix, indent, depth)
   104				}
   105				dst.WriteByte(c)
   106	
   107			default:
   108				dst.WriteByte(c)
   109			}
   110		}
   111		if scan.eof() == scanError {
   112			dst.Truncate(origLen)
   113			return scan.err
   114		}
   115		return nil
   116	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.