json.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. package xpj
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "io"
  8. )
  9. // ParseJSON builds a tree from one JSON document. Numbers keep their text.
  10. func ParseJSON(body []byte) (*Node, error) {
  11. dec := json.NewDecoder(bytes.NewReader(body))
  12. dec.UseNumber()
  13. root, err := parseValue(dec)
  14. if err != nil {
  15. return nil, err
  16. }
  17. if _, err := dec.Token(); err != io.EOF {
  18. if err == nil {
  19. err = errors.New("unexpected data after the document")
  20. }
  21. return nil, fmt.Errorf("xpj: %w", err)
  22. }
  23. return root, nil
  24. }
  25. func parseValue(dec *json.Decoder) (*Node, error) {
  26. tok, err := dec.Token()
  27. if err != nil {
  28. if err == io.EOF {
  29. err = io.ErrUnexpectedEOF
  30. }
  31. return nil, fmt.Errorf("xpj: %w", err)
  32. }
  33. switch t := tok.(type) {
  34. case nil:
  35. return NewNull(), nil
  36. case bool:
  37. return NewBool(t), nil
  38. case json.Number:
  39. return &Node{Kind: Number, Text: string(t)}, nil
  40. case string:
  41. return NewString(t), nil
  42. case json.Delim:
  43. switch t {
  44. case '[':
  45. n := &Node{Kind: Array, Items: []*Node{}}
  46. for dec.More() {
  47. v, err := parseValue(dec)
  48. if err != nil {
  49. return nil, err
  50. }
  51. n.Items = append(n.Items, v)
  52. }
  53. _, err := dec.Token() // ]
  54. return n, wrapErr(err)
  55. case '{':
  56. n := &Node{Kind: Object, Members: []Member{}}
  57. for dec.More() {
  58. kt, err := dec.Token()
  59. if err != nil {
  60. return nil, wrapErr(err)
  61. }
  62. v, err := parseValue(dec)
  63. if err != nil {
  64. return nil, err
  65. }
  66. n.Members = append(n.Members, Member{Key: kt.(string), Value: v})
  67. }
  68. _, err := dec.Token() // }
  69. return n, wrapErr(err)
  70. }
  71. }
  72. return nil, fmt.Errorf("xpj: unexpected token %v", tok)
  73. }
  74. // wrapErr prefixes a JSON decoding error with the package name.
  75. func wrapErr(err error) error {
  76. if err == nil {
  77. return nil
  78. }
  79. return fmt.Errorf("xpj: %w", err)
  80. }
  81. // MarshalJSON writes n in the device's layout: one key or value per line, no
  82. // indentation, ": " after keys, "," at line ends, empty containers as [] and
  83. // {}, no trailing newline.
  84. func (n *Node) MarshalJSON() ([]byte, error) {
  85. var b bytes.Buffer
  86. if err := writeValue(&b, n); err != nil {
  87. return nil, err
  88. }
  89. return b.Bytes(), nil
  90. }
  91. func writeValue(b *bytes.Buffer, n *Node) error {
  92. if n == nil {
  93. return errors.New("xpj: nil node in tree")
  94. }
  95. switch n.Kind {
  96. case Null:
  97. b.WriteString("null")
  98. case Bool:
  99. if n.Bool {
  100. b.WriteString("true")
  101. } else {
  102. b.WriteString("false")
  103. }
  104. case Number:
  105. if !isNumber(n.Text) {
  106. return fmt.Errorf("xpj: invalid number text %q", n.Text)
  107. }
  108. b.WriteString(n.Text)
  109. case String:
  110. writeString(b, n.Text)
  111. case Array:
  112. if len(n.Items) == 0 {
  113. b.WriteString("[]")
  114. return nil
  115. }
  116. b.WriteString("[\n")
  117. for i, it := range n.Items {
  118. if i > 0 {
  119. b.WriteString(",\n")
  120. }
  121. if err := writeValue(b, it); err != nil {
  122. return err
  123. }
  124. }
  125. b.WriteString("\n]")
  126. case Object:
  127. if len(n.Members) == 0 {
  128. b.WriteString("{}")
  129. return nil
  130. }
  131. b.WriteString("{\n")
  132. for i, m := range n.Members {
  133. if i > 0 {
  134. b.WriteString(",\n")
  135. }
  136. writeString(b, m.Key)
  137. b.WriteString(": ")
  138. if err := writeValue(b, m.Value); err != nil {
  139. return err
  140. }
  141. }
  142. b.WriteString("\n}")
  143. default:
  144. return fmt.Errorf("xpj: unknown node kind %d", n.Kind)
  145. }
  146. return nil
  147. }
  148. // writeString escapes like the reference writer (Python json, ensure_ascii
  149. // off): quote, backslash and control characters only. '<', '>', '&', '/' and
  150. // non-ASCII text are written as they are.
  151. func writeString(b *bytes.Buffer, s string) {
  152. const hex = "0123456789abcdef"
  153. b.WriteByte('"')
  154. for i := 0; i < len(s); i++ {
  155. c := s[i]
  156. switch c {
  157. case '"':
  158. b.WriteString(`\"`)
  159. case '\\':
  160. b.WriteString(`\\`)
  161. case '\n':
  162. b.WriteString(`\n`)
  163. case '\r':
  164. b.WriteString(`\r`)
  165. case '\t':
  166. b.WriteString(`\t`)
  167. case '\b':
  168. b.WriteString(`\b`)
  169. case '\f':
  170. b.WriteString(`\f`)
  171. default:
  172. if c < 0x20 {
  173. b.WriteString(`\u00`)
  174. b.WriteByte(hex[c>>4])
  175. b.WriteByte(hex[c&0xf])
  176. } else {
  177. b.WriteByte(c)
  178. }
  179. }
  180. }
  181. b.WriteByte('"')
  182. }
  183. // isNumber reports whether s is a JSON number literal.
  184. func isNumber(s string) bool {
  185. i := 0
  186. if i < len(s) && s[i] == '-' {
  187. i++
  188. }
  189. switch {
  190. case i < len(s) && s[i] == '0':
  191. i++
  192. case i < len(s) && s[i] >= '1' && s[i] <= '9':
  193. for i < len(s) && s[i] >= '0' && s[i] <= '9' {
  194. i++
  195. }
  196. default:
  197. return false
  198. }
  199. if i < len(s) && s[i] == '.' {
  200. i++
  201. start := i
  202. for i < len(s) && s[i] >= '0' && s[i] <= '9' {
  203. i++
  204. }
  205. if i == start {
  206. return false
  207. }
  208. }
  209. if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
  210. i++
  211. if i < len(s) && (s[i] == '+' || s[i] == '-') {
  212. i++
  213. }
  214. start := i
  215. for i < len(s) && s[i] >= '0' && s[i] <= '9' {
  216. i++
  217. }
  218. if i == start {
  219. return false
  220. }
  221. }
  222. return i == len(s)
  223. }