项目作者: go-restit

项目描述 :
A flexible JSON decoding library in Golang
高级语言: Go
项目地址: git://github.com/go-restit/lzjson.git
创建时间: 2016-02-06T18:20:07Z
项目社区:https://github.com/go-restit/lzjson

开源协议:MIT License

下载


lzjson GoDoc Travis CI results AppVeyor Coverage Status

lzjson is a JSON decoding library aims to make you lazy.

Golang default JSON library requires to
provide certain data structure (e.g. struct) to decode data to. It is hard to
write type-inspecific code to examine JSON data structure. It is also hard to
determine the abcence or prescence of data field.

This library provide flexible interface for writing generic JSON parsing code.

Key features:

  • zero knowledge parsing: can read and examine JSON structure without
    pre-defining the data structure before hand.

  • lazy parsing: allow you to parse only a specific node into golang data
    structure.

  • compatibility: totally compatible with the default json library

Example Use

Decode a JSON

Decode is straight forward with any io.Reader
implementation (e.g.
http.Request.Body,
http.Response.Body,
strings.Reader).

For example, in a http.HandlerFunc:

  1. import (
  2. "net/http"
  3. "github.com/go-restit/lzjson"
  4. )
  5. func handler(w http.ResponseWriter, r *http.Request) {
  6. json := lzjson.Decode(r.Body)
  7. ...
  8. ...
  9. }

Or as a client:

  1. func main() {
  2. resp, _ := http.Get("http://foobarapi.com/things")
  3. json := lzjson.Decode(resp.Body)
  4. ...
  5. ...
  6. }

Get a node in an object or an array

You may retrieve the JSON value of any node.

  1. // get "foo" in the json
  2. foo := json.Get("foo")
  3. // get the 10th item in foo
  4. // (like ordinary array, 0 is the first)
  5. item10 := foo.GetN(9)

Every node knows what it is

  1. body := strings.NewReader(`
  2. {
  3. "string": "hello world",
  4. "number": 3.14,
  5. "bool": true,
  6. "array": [1, 2, 3, 5],
  7. "object": {"foo": "bar"}
  8. }
  9. `)
  10. json := lzjson.Decode(body)
  11. fmt.Printf("%s", json.Get("string").Type()) // output "TypeString"
  12. fmt.Printf("%s", json.Get("number").Type()) // output "TypeNumber"
  13. fmt.Printf("%s", json.Get("bool").Type()) // output "TypeBool"
  14. fmt.Printf("%s", json.Get("array").Type()) // output "TypeArray"
  15. fmt.Printf("%s", json.Get("object").Type()) // output "TypeObject"

Evaluating values a JSON node

For basic value types (string, int, bool), you may evaluate them directly.

  1. code := json.Get("code").Int()
  2. message := json.Get("message").String()

Partial Unmarsaling

You may decode only a child-node in a JSON structure.

  1. type Item struct {
  2. Name string `json:"name"`
  3. Weight int `json:"weight"`
  4. }
  5. var item Item
  6. item10 := foo.GetN(9)
  7. item10.Unmarshal(&item)
  8. log.Printf("item: name=%s, weight=%d", item.Name, item.Weight)

Chaining

You may chain Get and GetN to get somthing deep within.

  1. helloIn10thBar := lzjson.Decode(r.Body).Get("foo").GetN(9).Get("hello")

Looping Object or Array

Looping is straight forward with Len and GetKeys.

  1. var item Item
  2. for i := 0; i<foo.Len(); i++ {
  3. foo.Get(i).Unmarshal(&item)
  4. log.Printf("i=%d, value=%#v", i, item)
  5. }
  6. for _, key := range json.GetKeys() {
  7. log.Printf("key=%#v, value=%#v", key, json.Get(key).String())
  8. }

Error knows their location

With chaining, it is important where exactly did any parse error happen.

  1. body := strings.NewReader(`
  2. {
  3. "hello": [
  4. {
  5. "name": "world 1"
  6. },
  7. {
  8. "name": "world 2"
  9. },
  10. {
  11. "name": "world 3"
  12. },
  13. ],
  14. }
  15. `)
  16. json := lzjson.Decode(body)
  17. inner := json.Get("hello").GetN(2).Get("foo").Get("bar").GetN(0)
  18. if err := inner.ParseError(); err != nil {
  19. fmt.Println(err.Error()) // output: "hello[2].foo: undefined"
  20. }

Full Example

Put everything above together, we can do something like this:

  1. package main
  2. import (
  3. "log"
  4. "net/http"
  5. "github.com/go-restit/lzjson"
  6. )
  7. type Thing struct {
  8. ID string `json:"id"`
  9. Name string `json:"name"`
  10. Found time.Time `json:"found"`
  11. FromEarth bool `json:"from_earth"`
  12. }
  13. /**
  14. * assume the API endpoints returns data:
  15. * {
  16. * "code": 200,
  17. * "data": [
  18. * ...
  19. * ]
  20. * }
  21. *
  22. * or error:
  23. * {
  24. * "code": 500,
  25. * "message": "some error message"
  26. * }
  27. *
  28. */
  29. func main() {
  30. resp, err := http.Get("http://foobarapi.com/things")
  31. if err != nil {
  32. panic(err)
  33. }
  34. // decode the json as usual, if no error
  35. json := lzjson.Decode(resp.Body)
  36. if code := json.Get("code").Int(); code != 200 {
  37. message := json.Get("message").String()
  38. log.Fatalf("error %d: ", code, message)
  39. }
  40. // get the things array
  41. things := json.Get("data")
  42. // loop through the array
  43. for i := 0; i<things.Len(); i++ {
  44. thing := things.GetN(i)
  45. if err := thing.ParseError(); err != nil {
  46. log.Fatal(err.Error())
  47. }
  48. // if the thing is not from earth, unmarshal
  49. // as a struct then read the details
  50. if !thing.Get("from_earth").Bool() {
  51. var theThing Thing
  52. thing.Unmarshal(&theThing)
  53. log.Printf("Alien found! %#v", theThing)
  54. }
  55. }
  56. }

For more details, please read the documentation

Contirbuting

Your are welcome to contribute to this library.

To report bug, please use the issue tracker.

To fix an existing bug or implement a new feature, please:

  1. Check the issue tracker and pull requests for existing discussion.
  2. If not, please open a new issue for discussion.
  3. Write tests.
  4. Open a pull request referencing the issue.
  5. Have fun :-)

Licence

This software is licenced with the MIT Licence.
You can obtain a copy of the licence in this repository.