json.go 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. // Copyright 2012-2014 Charles Banning. 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. package mxj
  5. import (
  6. "bytes"
  7. "encoding/json"
  8. "fmt"
  9. "io"
  10. "time"
  11. )
  12. // ------------------------------ write JSON -----------------------
  13. // Just a wrapper on json.Marshal.
  14. // If option safeEncoding is'true' then safe encoding of '<', '>' and '&'
  15. // is preserved. (see encoding/json#Marshal, encoding/json#Encode)
  16. func (mv Map) Json(safeEncoding ...bool) ([]byte, error) {
  17. var s bool
  18. if len(safeEncoding) == 1 {
  19. s = safeEncoding[0]
  20. }
  21. b, err := json.Marshal(mv)
  22. if !s {
  23. b = bytes.Replace(b, []byte("\\u003c"), []byte("<"), -1)
  24. b = bytes.Replace(b, []byte("\\u003e"), []byte(">"), -1)
  25. b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1)
  26. }
  27. return b, err
  28. }
  29. // Just a wrapper on json.MarshalIndent.
  30. // If option safeEncoding is'true' then safe encoding of '<' , '>' and '&'
  31. // is preserved. (see encoding/json#Marshal, encoding/json#Encode)
  32. func (mv Map) JsonIndent(prefix, indent string, safeEncoding ...bool) ([]byte, error) {
  33. var s bool
  34. if len(safeEncoding) == 1 {
  35. s = safeEncoding[0]
  36. }
  37. b, err := json.MarshalIndent(mv, prefix, indent)
  38. if !s {
  39. b = bytes.Replace(b, []byte("\\u003c"), []byte("<"), -1)
  40. b = bytes.Replace(b, []byte("\\u003e"), []byte(">"), -1)
  41. b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1)
  42. }
  43. return b, err
  44. }
  45. // The following implementation is provided for symmetry with NewMapJsonReader[Raw]
  46. // The names will also provide a key for the number of return arguments.
  47. // Writes the Map as JSON on the Writer.
  48. // If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved.
  49. func (mv Map) JsonWriter(jsonWriter io.Writer, safeEncoding ...bool) error {
  50. b, err := mv.Json(safeEncoding...)
  51. if err != nil {
  52. return err
  53. }
  54. _, err = jsonWriter.Write(b)
  55. return err
  56. }
  57. // Writes the Map as JSON on the Writer. []byte is the raw JSON that was written.
  58. // If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved.
  59. func (mv Map) JsonWriterRaw(jsonWriter io.Writer, safeEncoding ...bool) ([]byte, error) {
  60. b, err := mv.Json(safeEncoding...)
  61. if err != nil {
  62. return b, err
  63. }
  64. _, err = jsonWriter.Write(b)
  65. return b, err
  66. }
  67. // Writes the Map as pretty JSON on the Writer.
  68. // If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved.
  69. func (mv Map) JsonIndentWriter(jsonWriter io.Writer, prefix, indent string, safeEncoding ...bool) error {
  70. b, err := mv.JsonIndent(prefix, indent, safeEncoding...)
  71. if err != nil {
  72. return err
  73. }
  74. _, err = jsonWriter.Write(b)
  75. return err
  76. }
  77. // Writes the Map as pretty JSON on the Writer. []byte is the raw JSON that was written.
  78. // If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved.
  79. func (mv Map) JsonIndentWriterRaw(jsonWriter io.Writer, prefix, indent string, safeEncoding ...bool) ([]byte, error) {
  80. b, err := mv.JsonIndent(prefix, indent, safeEncoding...)
  81. if err != nil {
  82. return b, err
  83. }
  84. _, err = jsonWriter.Write(b)
  85. return b, err
  86. }
  87. // --------------------------- read JSON -----------------------------
  88. // Decode numericvalues as json.Number type Map values - see encoding/json#Number.
  89. // NOTE: this is for decoding JSON into a Map with NewMapJson(), NewMapJsonReader(),
  90. // etc.; it does not affect NewMapXml(), etc. The XML encoders mv.Xml() and mv.XmlIndent()
  91. // do recognize json.Number types; a JSON object can be decoded to a Map with json.Number
  92. // value types and the resulting Map can be correctly encoded into a XML object.
  93. var JsonUseNumber bool
  94. // Just a wrapper on json.Unmarshal
  95. // Converting JSON to XML is a simple as:
  96. // ...
  97. // mapVal, merr := mxj.NewMapJson(jsonVal)
  98. // if merr != nil {
  99. // // handle error
  100. // }
  101. // xmlVal, xerr := mapVal.Xml()
  102. // if xerr != nil {
  103. // // handle error
  104. // }
  105. // NOTE: as a special case, passing a list, e.g., [{"some-null-value":"", "a-non-null-value":"bar"}],
  106. // will be interpreted as having the root key 'object' prepended - {"object":[ ... ]} - to unmarshal to a Map.
  107. // See mxj/j2x/j2x_test.go.
  108. func NewMapJson(jsonVal []byte) (Map, error) {
  109. // empty or nil begets empty
  110. if len(jsonVal) == 0 {
  111. m := make(map[string]interface{}, 0)
  112. return m, nil
  113. }
  114. // handle a goofy case ...
  115. if jsonVal[0] == '[' {
  116. jsonVal = []byte(`{"object":` + string(jsonVal) + `}`)
  117. }
  118. m := make(map[string]interface{})
  119. // err := json.Unmarshal(jsonVal, &m)
  120. buf := bytes.NewReader(jsonVal)
  121. dec := json.NewDecoder(buf)
  122. if JsonUseNumber {
  123. dec.UseNumber()
  124. }
  125. err := dec.Decode(&m)
  126. return m, err
  127. }
  128. // Retrieve a Map value from an io.Reader.
  129. // NOTE: The raw JSON off the reader is buffered to []byte using a ByteReader. If the io.Reader is an
  130. // os.File, there may be significant performance impact. If the io.Reader is wrapping a []byte
  131. // value in-memory, however, such as http.Request.Body you CAN use it to efficiently unmarshal
  132. // a JSON object.
  133. func NewMapJsonReader(jsonReader io.Reader) (Map, error) {
  134. jb, err := getJson(jsonReader)
  135. if err != nil || len(*jb) == 0 {
  136. return nil, err
  137. }
  138. // Unmarshal the 'presumed' JSON string
  139. return NewMapJson(*jb)
  140. }
  141. // Retrieve a Map value and raw JSON - []byte - from an io.Reader.
  142. // NOTE: The raw JSON off the reader is buffered to []byte using a ByteReader. If the io.Reader is an
  143. // os.File, there may be significant performance impact. If the io.Reader is wrapping a []byte
  144. // value in-memory, however, such as http.Request.Body you CAN use it to efficiently unmarshal
  145. // a JSON object and retrieve the raw JSON in a single call.
  146. func NewMapJsonReaderRaw(jsonReader io.Reader) (Map, []byte, error) {
  147. jb, err := getJson(jsonReader)
  148. if err != nil || len(*jb) == 0 {
  149. return nil, *jb, err
  150. }
  151. // Unmarshal the 'presumed' JSON string
  152. m, merr := NewMapJson(*jb)
  153. return m, *jb, merr
  154. }
  155. // Pull the next JSON string off the stream: just read from first '{' to its closing '}'.
  156. // Returning a pointer to the slice saves 16 bytes - maybe unnecessary, but internal to package.
  157. func getJson(rdr io.Reader) (*[]byte, error) {
  158. bval := make([]byte, 1)
  159. jb := make([]byte, 0)
  160. var inQuote, inJson bool
  161. var parenCnt int
  162. var previous byte
  163. // scan the input for a matched set of {...}
  164. // json.Unmarshal will handle syntax checking.
  165. for {
  166. _, err := rdr.Read(bval)
  167. if err != nil {
  168. if err == io.EOF && inJson && parenCnt > 0 {
  169. return &jb, fmt.Errorf("no closing } for JSON string: %s", string(jb))
  170. }
  171. return &jb, err
  172. }
  173. switch bval[0] {
  174. case '{':
  175. if !inQuote {
  176. parenCnt++
  177. inJson = true
  178. }
  179. case '}':
  180. if !inQuote {
  181. parenCnt--
  182. }
  183. if parenCnt < 0 {
  184. return nil, fmt.Errorf("closing } without opening {: %s", string(jb))
  185. }
  186. case '"':
  187. if inQuote {
  188. if previous == '\\' {
  189. break
  190. }
  191. inQuote = false
  192. } else {
  193. inQuote = true
  194. }
  195. case '\n', '\r', '\t', ' ':
  196. if !inQuote {
  197. continue
  198. }
  199. }
  200. if inJson {
  201. jb = append(jb, bval[0])
  202. if parenCnt == 0 {
  203. break
  204. }
  205. }
  206. previous = bval[0]
  207. }
  208. return &jb, nil
  209. }
  210. // ------------------------------- JSON Reader handler via Map values -----------------------
  211. // Default poll delay to keep Handler from spinning on an open stream
  212. // like sitting on os.Stdin waiting for imput.
  213. var jhandlerPollInterval = time.Duration(1e6)
  214. // While unnecessary, we make HandleJsonReader() have the same signature as HandleXmlReader().
  215. // This avoids treating one or other as a special case and discussing the underlying stdlib logic.
  216. // Bulk process JSON using handlers that process a Map value.
  217. // 'rdr' is an io.Reader for the JSON (stream).
  218. // 'mapHandler' is the Map processing handler. Return of 'false' stops io.Reader processing.
  219. // 'errHandler' is the error processor. Return of 'false' stops io.Reader processing and returns the error.
  220. // Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized.
  221. // This means that you can stop reading the file on error or after processing a particular message.
  222. // To have reading and handling run concurrently, pass argument to a go routine in handler and return 'true'.
  223. func HandleJsonReader(jsonReader io.Reader, mapHandler func(Map) bool, errHandler func(error) bool) error {
  224. var n int
  225. for {
  226. m, merr := NewMapJsonReader(jsonReader)
  227. n++
  228. // handle error condition with errhandler
  229. if merr != nil && merr != io.EOF {
  230. merr = fmt.Errorf("[jsonReader: %d] %s", n, merr.Error())
  231. if ok := errHandler(merr); !ok {
  232. // caused reader termination
  233. return merr
  234. }
  235. continue
  236. }
  237. // pass to maphandler
  238. if len(m) != 0 {
  239. if ok := mapHandler(m); !ok {
  240. break
  241. }
  242. } else if merr != io.EOF {
  243. <-time.After(jhandlerPollInterval)
  244. }
  245. if merr == io.EOF {
  246. break
  247. }
  248. }
  249. return nil
  250. }
  251. // Bulk process JSON using handlers that process a Map value and the raw JSON.
  252. // 'rdr' is an io.Reader for the JSON (stream).
  253. // 'mapHandler' is the Map and raw JSON - []byte - processor. Return of 'false' stops io.Reader processing.
  254. // 'errHandler' is the error and raw JSON processor. Return of 'false' stops io.Reader processing and returns the error.
  255. // Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized.
  256. // This means that you can stop reading the file on error or after processing a particular message.
  257. // To have reading and handling run concurrently, pass argument(s) to a go routine in handler and return 'true'.
  258. func HandleJsonReaderRaw(jsonReader io.Reader, mapHandler func(Map, []byte) bool, errHandler func(error, []byte) bool) error {
  259. var n int
  260. for {
  261. m, raw, merr := NewMapJsonReaderRaw(jsonReader)
  262. n++
  263. // handle error condition with errhandler
  264. if merr != nil && merr != io.EOF {
  265. merr = fmt.Errorf("[jsonReader: %d] %s", n, merr.Error())
  266. if ok := errHandler(merr, raw); !ok {
  267. // caused reader termination
  268. return merr
  269. }
  270. continue
  271. }
  272. // pass to maphandler
  273. if len(m) != 0 {
  274. if ok := mapHandler(m, raw); !ok {
  275. break
  276. }
  277. } else if merr != io.EOF {
  278. <-time.After(jhandlerPollInterval)
  279. }
  280. if merr == io.EOF {
  281. break
  282. }
  283. }
  284. return nil
  285. }