在Go语言中解析嵌套的JSON。

huangapple go评论89阅读模式
英文:

Parsing nested JSON in go language

问题

如何解析和提取以下JSON中的特定值?

这是示例JSON响应:

{
   "success":true,
   "endpoint":"https://api.abcxyz.com",
   "info":{
      "Guestconnected":134,
      "Guestratio":100000.06963,
      "symbol1":{
         "code":"NY",
         "symbol":"*",
         "name":"newyear",
         "codev":391.78161,
         "symbolAppearsAfter":false,
         "local":true
      },
      "symbol2":{
         "code":"HNY",
         "symbol":"@",
         "name":"HappyNewYear",
         "codev":1000000.0960,
         "symbolAppearsAfter":true,
         "local":false
      },
      "latest":{
         "value":1597509,
         "autovalue":"00099cf8da58a36c08f2ef98650ff6043ddfb",
         "height":474696,
         "time":1499527696
      }
   },
   "Allguest":{
      "all":4,
      "filtered":4,
      "total_invitations":15430,
      "sent_invitations":15430,
      "final_invitations":0
   },
   "Guestlist":[
      {
         "GuestCode":"369AR",
         "all":2,
         "total_invitations":5430,
         "sent_invitations":5430,
         "final_invitations":0,
         "change":0,
         "accounts":0
      },
      {
         "GuestCode":"6POIA96TY",
         "all":2,
         "total_invitations":10000,
         "sent_invitations":10000,
         "final_invitations":0,
         "change":0,
         "accounts":0
      }
   ]
}

我的代码是:

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
)


type object struct {
    Success bool `json:"success"`
    Endpoint string `json:"endpoint"`
    Allguest struct {
        All int `json:"all"`
        Filtered int `json:"filtered"`
        TotalInvitations int `json:"total_invitations"`
        SentInvitations int `json:"sent_invitations"`
        FinalInvitations int `json:"final_invitations"`
    } `json:"Allguest"`
    Guestlist []struct {
        GuestCode string `json:"GuestCode"`
        All int `json:"all"`
        TotalInvitations int `json:"total_invitations"`
        SentInvitations int `json:"sent_invitations"`
        FinalInvitations int `json:"final_invitations"`
        Change int `json:"change"`
        Accounts int `json:"accounts"`
    } `json:"Guestlist"`
}

func main() {

uri := "https://siteurl.com/api?lists=1"
res, err := http.Get(uri)
fmt.Println(uri)
if err != nil {
fmt.Println("Error:", err)
    log.Fatal(err)
}
defer res.Body.Close()

 var s object
err := json.NewDecoder(res.Body).Decode(&s)
if err != nil {
    log.Fatal(err)
    fmt.Println("Error:", err)
}
fmt.Println(s.Success)
fmt.Println(s.Allguest.TotalInvitations)
for i := 0; i < 6; i++ {
fmt.Println(s.Guestlist[i].TotalInvitations)
}

}

问题是:

  1. 如果响应为空,它会给出“索引超出范围错误”,我们如何避免这种情况?

  2. 如果TotalInvitations的值大于100,则将其保存在100.csv中,否则保存在others.csv中。

英文:

How could I parse and extract certain values from below JSON

Here is the sample JSON response

{
&quot;success&quot;:true,
&quot;endpoint&quot;:&quot;https://api.abcxyz.com&quot;,
&quot;info&quot;:{
&quot;Guestconnected&quot;:134,
&quot;Guestratio&quot;:100000.06963,
&quot;symbol1&quot;:{
&quot;code&quot;:&quot;NY&quot;,
&quot;symbol&quot;:&quot;*&quot;,
&quot;name&quot;:&quot;newyear&quot;,
&quot;codev&quot;:391.78161,
&quot;symbolAppearsAfter&quot;:false,
&quot;local&quot;:true
},
&quot;symbol2&quot;:{
&quot;code&quot;:&quot;HNY&quot;,
&quot;symbol&quot;:&quot;@&quot;,
&quot;name&quot;:&quot;HappyNewYear&quot;,
&quot;codev&quot;:1000000.0960,
&quot;symbolAppearsAfter&quot;:true,
&quot;local&quot;:false
},
&quot;latest&quot;:{
&quot;value&quot;:1597509,
&quot;autovalue&quot;:&quot;00099cf8da58a36c08f2ef98650ff6043ddfb&quot;,
&quot;height&quot;:474696,
&quot;time&quot;:1499527696
}
},
&quot;Allguest&quot;:{
&quot;all&quot;:4,
&quot;filtered&quot;:4,
&quot;total_invitations&quot;:15430,
&quot;sent_invitations&quot;:15430,
&quot;final_invitations&quot;:0
},
&quot;Guestlist&quot;:[
{
&quot;GuestCode&quot;:&quot;369AR&quot;,
&quot;all&quot;:2,
&quot;total_invitations&quot;:5430,
&quot;sent_invitations&quot;:5430,
&quot;final_invitations&quot;:0,
&quot;change&quot;:0,
&quot;accounts&quot;:0
},
{
&quot;GuestCode&quot;:&quot;6POIA96TY&quot;,
&quot;all&quot;:2,
&quot;total_invitations&quot;:10000,
&quot;sent_invitations&quot;:10000,
&quot;final_invitations&quot;:0,
&quot;change&quot;:0,
&quot;accounts&quot;:0
}
]
}

My Code is :

package main
import (
&quot;encoding/json&quot;
&quot;fmt&quot;
&quot;log&quot;
&quot;net/http&quot;
)
type object struct {
Success bool `json:&quot;success&quot;`
Endpoint string `json:&quot;endpoint&quot;`
Allguest struct {
All int `json:&quot;all&quot;`
Filtered int `json:&quot;filtered&quot;`
TotalInvitations int `json:&quot;total_invitations&quot;`
SentInvitations int `json:&quot;sent_invitations&quot;`
FinalInvitations int `json:&quot;final_invitations&quot;`
} `json:&quot;Allguest&quot;`
Guestlist []struct {
GuestCode string `json:&quot;GuestCode&quot;`
All int `json:&quot;all&quot;`
TotalInvitations int `json:&quot;total_invitations&quot;`
SentInvitations int `json:&quot;sent_invitations&quot;`
FinalInvitations int `json:&quot;final_invitations&quot;`
Change int `json:&quot;change&quot;`
Accounts int `json:&quot;accounts&quot;`
} `json:&quot;Guestlist&quot;`
}
func main() {
uri := &quot;https://siteurl.com/api?lists=1&quot;
res, err := http.Get(uri)
fmt.Println(uri)
if err != nil {
fmt.Println(&quot;Error:&quot;, err)
log.Fatal(err)
}
defer res.Body.Close()
var s object
err := json.NewDecoder(res.Body).Decode(&amp;s)
if err != nil {
log.Fatal(err)
fmt.Println(&quot;Error:&quot;, err)
}
fmt.Println(s.Success)
fmt.Println(s.Allguest.TotalInvitations)
for i := 0; i &lt; 6; i++ {
fmt.Println(s.Guestlist[i].TotalInvitations)
)
}

The problem is :

  1. If the response is null it is giving index out of range error how can we avoid this ?

  2. Applying condition if TotalInvitations value is greater than 100 then save in 100.csv else save in others.csv

答案1

得分: 1

如果您只需要从JSON中获取特定的条目,您可以定义一个只包含您感兴趣的字段的结构。如果值可以为null,最好在结构中声明一个指针。请查看Go Playground上的示例:https://play.golang.org/p/mEwSXvPg3D

英文:

If you need only certain entries from JSON you can define a structure with only those fields you are interested in. And if value can be null it is better to declare a pointer in the structure. Please take a look at an example at go playground: https://play.golang.org/p/mEwSXvPg3D

答案2

得分: 0

使用gjson包以简单的方式从JSON文档中获取值

示例:

package main

import (
	"fmt"

	"github.com/tidwall/gjson"
)

func main() {
	data := []byte(`{
   "success": true,
   "endpoint": "https://api.abcxyz.com",
   "info": {
      "Guestconnected": 134,
      "Guestratio": 100000.06963,
      "symbol1": {
         "code": "NY",
         "symbol": "*",
         "name": "newyear",
         "codev": 391.78161,
         "symbolAppearsAfter": false,
         "local": true
      },
      "symbol2": {
         "code": "HNY",
         "symbol": "@",
         "name": "HappyNewYear",
         "codev": 1000000.096,
         "symbolAppearsAfter": true,
         "local": false
      },
      "latest": {
         "value": 1597509,
         "autovalue": "00099cf8da58a36c08f2ef98650ff6043ddfb",
         "height": 474696,
         "time": 1499527696
      }
   },
   "Allguest": {
      "all": 4,
      "filtered": 4,
      "total_invitations": 15430,
      "sent_invitations": 15430,
      "final_invitations": 0
   },
   "Guestlist": [
      {
         "GuestCode": "369AR",
         "all": 2,
         "total_invitations": 5430,
         "sent_invitations": 5430,
         "final_invitations": 0,
         "change": 0,
         "accounts": 0
      },
      {
         "GuestCode": "6POIA96TY",
         "all": 2,
         "total_invitations": 10000,
         "sent_invitations": 10000,
         "final_invitations": 0,
         "change": 0,
         "accounts": 0
      }
   ]
	}
	`)

	r := gjson.GetBytes(data, "Allguest.total_invitations")
	fmt.Println(r.Value()) // 输出 15430

	r = gjson.GetBytes(data, "Guestlist.#.total_invitations")
	fmt.Println(r.Value()) // 输出 [5430 10000]
}
英文:

use gjson pkg to get value from json document an simple way

example:

package main
import (
&quot;fmt&quot;
&quot;github.com/tidwall/gjson&quot;
)
func main() {
data := []byte(`{
&quot;success&quot;: true,
&quot;endpoint&quot;: &quot;https://api.abcxyz.com&quot;,
&quot;info&quot;: {
&quot;Guestconnected&quot;: 134,
&quot;Guestratio&quot;: 100000.06963,
&quot;symbol1&quot;: {
&quot;code&quot;: &quot;NY&quot;,
&quot;symbol&quot;: &quot;*&quot;,
&quot;name&quot;: &quot;newyear&quot;,
&quot;codev&quot;: 391.78161,
&quot;symbolAppearsAfter&quot;: false,
&quot;local&quot;: true
},
&quot;symbol2&quot;: {
&quot;code&quot;: &quot;HNY&quot;,
&quot;symbol&quot;: &quot;@&quot;,
&quot;name&quot;: &quot;HappyNewYear&quot;,
&quot;codev&quot;: 1000000.096,
&quot;symbolAppearsAfter&quot;: true,
&quot;local&quot;: false
},
&quot;latest&quot;: {
&quot;value&quot;: 1597509,
&quot;autovalue&quot;: &quot;00099cf8da58a36c08f2ef98650ff6043ddfb&quot;,
&quot;height&quot;: 474696,
&quot;time&quot;: 1499527696
}
},
&quot;Allguest&quot;: {
&quot;all&quot;: 4,
&quot;filtered&quot;: 4,
&quot;total_invitations&quot;: 15430,
&quot;sent_invitations&quot;: 15430,
&quot;final_invitations&quot;: 0
},
&quot;Guestlist&quot;: [
{
&quot;GuestCode&quot;: &quot;369AR&quot;,
&quot;all&quot;: 2,
&quot;total_invitations&quot;: 5430,
&quot;sent_invitations&quot;: 5430,
&quot;final_invitations&quot;: 0,
&quot;change&quot;: 0,
&quot;accounts&quot;: 0
},
{
&quot;GuestCode&quot;: &quot;6POIA96TY&quot;,
&quot;all&quot;: 2,
&quot;total_invitations&quot;: 10000,
&quot;sent_invitations&quot;: 10000,
&quot;final_invitations&quot;: 0,
&quot;change&quot;: 0,
&quot;accounts&quot;: 0
}
]
}
`)
r := gjson.GetBytes(data, &quot;Allguest.total_invitations&quot;)
fmt.Println(r.Value()) // output 15430
r = gjson.GetBytes(data, &quot;Guestlist.#.total_invitations&quot;)
fmt.Println(r.Value()) // output [5430 10000]
}

答案3

得分: 0

> 如果响应为null,则会出现索引超出范围的错误,我们如何避免这种情况?

除非我误解了你的意思,响应为null不应该有影响。如果你收到了2个Guestlist项,你只能循环遍历这2个项,意味着for i := 0; i &lt; 6; i++是错误的。将其改为for i := 0; i &lt; len(s.Guestlist); i++for i := range s.Guestlist

> 如果TotalInvitations的值大于100,则保存在100.csv中,否则保存在others.csv中。

你可能需要使用os包的Create函数来创建一个新的文件用于写入,或者使用OpenFile函数、O_CREATEO_WRONLYO_APPEND文件打开标志,并且可以将0755作为权限模式(或者如果你想更改文件的访问权限,可以使用其他一组八进制权限)。

然后,你可以使用csvWriter := csv.NewWriter(csvFile)来包装生成的io.Writer(假设打开文件时没有错误)。然后,你可以将所需的任何信息以CSV记录的形式写入文件。不要忘记调用csvWriter.Flush来刷新输出缓冲区,以及使用csvWriter.Error来检查是否在刷新输出缓冲区时出现错误。还要记得关闭你打开的文件。

英文:

> If the response is null it is giving index out of range error how can
> we avoid this?

Unless I&#39;m misunderstanding you, the response being null shouldn&#39;t matter.  If you receive 2 Guestlist items, you can only loop over those 2, meaning `for i := 0; i &lt; 6; i++` is wrong.  Change it to `for i := 0; i &lt; len(s.Guestlist); i++` or `for i := range s.Guestlist`.

> Applying condition if TotalInvitations value is greater than 100 then
> save in 100.csv else save in others.csv

You will probably want the `os` package&#39;s [`Create`](https://golang.org/pkg/os/#Create) function to create a new file for writing or the [`OpenFile`](https://golang.org/pkg/os/#OpenFile) function, the [`O_CREATE`, `O_WRONLY`, and `O_APPEND`](https://golang.org/pkg/os/#O_WRONLY) file-open flags, and you can pass `0755` as the permission mode (or another set of octal permissions if you want to change access of a file).
You can then use `csvWriter := csv.NewWriter(csvFile)` to wrap the resulting `io.Writer` (assuming there is no error opening the file).  From there, you can just write whatever information you require to the file as CSV records.  Don&#39;t forget to call `csvWriter.Flush` to flush the output buffer and `csvWriter.Error` to check whether there was an error flushing the output buffer.  Also don&#39;t forget to close the file you opened.

huangapple
  • 本文由 发表于 2017年7月9日 00:25:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/44988335.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定