...

Source file src/encoding/json/indent.go

Documentation: encoding/json

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

View as plain text