json.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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, wrap(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, wrap(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, wrap(err)
  70. }
  71. }
  72. return nil, fmt.Errorf("xpj: unexpected token %v", tok)
  73. }
  74. func wrap(err error) error {
  75. if err == nil {
  76. return nil
  77. }
  78. return fmt.Errorf("xpj: %w", err)
  79. }
  80. // MarshalJSON writes n in the device's layout: one key or value per line, no
  81. // indentation, ": " after keys, "," at line ends, empty containers as [] and
  82. // {}, no trailing newline.
  83. func (n *Node) MarshalJSON() ([]byte, error) {
  84. var b bytes.Buffer
  85. if err := writeValue(&b, n); err != nil {
  86. return nil, err
  87. }
  88. return b.Bytes(), nil
  89. }
  90. func writeValue(b *bytes.Buffer, n *Node) error {
  91. if n == nil {
  92. return errors.New("xpj: nil node in tree")
  93. }
  94. switch n.Kind {
  95. case Null:
  96. b.WriteString("null")
  97. case Bool:
  98. if n.Bool {
  99. b.WriteString("true")
  100. } else {
  101. b.WriteString("false")
  102. }
  103. case Number:
  104. if !isNumber(n.Text) {
  105. return fmt.Errorf("xpj: invalid number text %q", n.Text)
  106. }
  107. b.WriteString(n.Text)
  108. case String:
  109. writeString(b, n.Text)
  110. case Array:
  111. if len(n.Items) == 0 {
  112. b.WriteString("[]")
  113. return nil
  114. }
  115. b.WriteString("[\n")
  116. for i, it := range n.Items {
  117. if i > 0 {
  118. b.WriteString(",\n")
  119. }
  120. if err := writeValue(b, it); err != nil {
  121. return err
  122. }
  123. }
  124. b.WriteString("\n]")
  125. case Object:
  126. if len(n.Members) == 0 {
  127. b.WriteString("{}")
  128. return nil
  129. }
  130. b.WriteString("{\n")
  131. for i, m := range n.Members {
  132. if i > 0 {
  133. b.WriteString(",\n")
  134. }
  135. writeString(b, m.Key)
  136. b.WriteString(": ")
  137. if err := writeValue(b, m.Value); err != nil {
  138. return err
  139. }
  140. }
  141. b.WriteString("\n}")
  142. default:
  143. return fmt.Errorf("xpj: unknown node kind %d", n.Kind)
  144. }
  145. return nil
  146. }
  147. // writeString escapes like the reference writer (Python json, ensure_ascii
  148. // off): quote, backslash and control characters only. '<', '>', '&', '/' and
  149. // non-ASCII text are written as they are.
  150. func writeString(b *bytes.Buffer, s string) {
  151. const hex = "0123456789abcdef"
  152. b.WriteByte('"')
  153. for i := 0; i < len(s); i++ {
  154. c := s[i]
  155. switch c {
  156. case '"':
  157. b.WriteString(`\"`)
  158. case '\\':
  159. b.WriteString(`\\`)
  160. case '\n':
  161. b.WriteString(`\n`)
  162. case '\r':
  163. b.WriteString(`\r`)
  164. case '\t':
  165. b.WriteString(`\t`)
  166. case '\b':
  167. b.WriteString(`\b`)
  168. case '\f':
  169. b.WriteString(`\f`)
  170. default:
  171. if c < 0x20 {
  172. b.WriteString(`\u00`)
  173. b.WriteByte(hex[c>>4])
  174. b.WriteByte(hex[c&0xf])
  175. } else {
  176. b.WriteByte(c)
  177. }
  178. }
  179. }
  180. b.WriteByte('"')
  181. }
  182. // isNumber reports whether s is a JSON number literal.
  183. func isNumber(s string) bool {
  184. i := 0
  185. if i < len(s) && s[i] == '-' {
  186. i++
  187. }
  188. switch {
  189. case i < len(s) && s[i] == '0':
  190. i++
  191. case i < len(s) && s[i] >= '1' && s[i] <= '9':
  192. for i < len(s) && s[i] >= '0' && s[i] <= '9' {
  193. i++
  194. }
  195. default:
  196. return false
  197. }
  198. if i < len(s) && s[i] == '.' {
  199. i++
  200. start := i
  201. for i < len(s) && s[i] >= '0' && s[i] <= '9' {
  202. i++
  203. }
  204. if i == start {
  205. return false
  206. }
  207. }
  208. if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
  209. i++
  210. if i < len(s) && (s[i] == '+' || s[i] == '-') {
  211. i++
  212. }
  213. start := i
  214. for i < len(s) && s[i] >= '0' && s[i] <= '9' {
  215. i++
  216. }
  217. if i == start {
  218. return false
  219. }
  220. }
  221. return i == len(s)
  222. }