github.com/qiniu/dyn@v1.3.0/text/internal/encoding/json/indent.go (about) 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 }