src/pkg/encoding/json/indent.go - The Go Programming Language

Golang

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