使用Go语言解析JSON时出现错误。

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

Error Parsing Json using Go language

问题

我正在尝试使用GO语言解析JSON并打印数据,然后将其保存在CSV文件中。

使用Println函数可以打印每页所需的10个结果,但无法解析JSON。

以下是我的操作步骤:

  1. 访问studentresults.com/page=1,显示10个学生的RollNo和Marks,并将其保存在CSV文件中(使用key.rollnokey.marks)。

  2. 程序向studentsapimarks.com/api/rollno1,rollno2,rollno3/detail发送请求(将步骤1中获取的所有key.rollno拼接在一起)。
    JSON响应如下:

     [{"name":"James","Percentage":96.5,"Remarks":"VeryGood"},
     {"name":"William","Percentage":36.0,"Remarks":"Bad"},
     {"name":"Jacob","Percentage":63.0,"Remarks":"Average"},
     {"name":"Wilson","Percentage":69.3,"Remarks":"Average"},
     {"name":"Kurtson","Percentage":16.9,"Remarks":"VeryBad"},
     {"name":"Tom","Percentage":86.3,"Remarks":"Good"}]
    
  3. 提取Name和Percentage字段,并保存在CSV文件中。

以下是负责打印和保存结果的代码片段:

package main

import (
    "encoding/csv"
    "fmt"
    "net/http"
    "os"
    "strings"
    "encoding/json"
)

type Key struct {
    fname  string
    marks  int
    rollno int
}

type object struct {
    Percentage float64
    Name       string `json:"name"`
}

func PageRequest(w http.ResponseWriter, r *http.Request) {
    // 页面头部
    fmt.Fprintf(w, PageHeader, pages, previous, next)

    // 保存到CSV文件
    csvfile, err := os.OpenFile("marks.csv", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    defer csvfile.Close()

    writer := csv.NewWriter(csvfile)
    defer writer.Flush()

    // 定义RollNos
    var rollNos []string

    // 计算UID的Marks
    UID, length := compute(start)
    for i := 0; i < length; i++ {
        key := UID[i]

        // 打印firstname、Marks和Rollno
        fmt.Fprintf(w, key.fname, key.marks, key.rollno)

        records := [][]string{{key.fname, key.marks, key.rollno}}

        for _, record := range records {
            err := writer.Write(record)
            if err != nil {
                fmt.Println("Error:", err)
                return
            }
        }

        // 添加所有的key.rollno
        rollNos := append(rollNos, key.rollno)

        // 发送请求到studentsapimarks.com/api/rollno1,rollno2,rollno3/detail
        uri := "https://studentsapimarks.com/api/" + strings.Join(rollNos, ",") + "/detail"

        res, err := http.Get(uri)
        if err != nil {
            log.Fatal(err)
        }
        defer res.Body.Close()

        var s []object
        err = json.NewDecoder(res.Body).Decode(&s)
        if err != nil {
            log.Fatal(err)
        }

        // 打印Name和Percentage
        fmt.Println(s[0].Name)
        fmt.Println(s[0].Percentage)
    }

    // 页面底部
    fmt.Fprintf(w, PageFooter, previous, next)
}

func main() {
    http.HandleFunc("/", PageRequest)

    log.Println("Listening")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

`fmt.Fprintf(w, key.fname, key.marks, key.rollno)`可以正常工作每页显示所有10个结果并保存在CSV文件中

代码的问题是

1. 没有将步骤1中获取的所有`key.rollno`追加到`studentsapimarks.com/api/rollno1,rollno2,rollno3/detail`

2. 如何将提取的JSON结果`s[0].name`保存到CSV文件中

<details>
<summary>英文:</summary>

I am trying to Parse Json &amp; Print Data and save in a CSV using GO language .

It is printing the desired 10 result per page with `Println` but couldn&#39;t parse JSON .

This is what I am doing

1. Visitor visits studentresults.com/page=1 RollNo. &amp; Marks for 10 students are displayed and it is also saved in a CSV [`key.rollno` &amp; `key.marks`]

2. Program Makes a request to `studentsapimarks.com/api/rollno1,rollno2,rollno3/detail` (appending all key.rollno that we got in step1)
The Json response would be like

        [{&quot;name&quot;:&quot;James&quot;,&quot;Percentage&quot;:96.5,&quot;Remarks&quot;:&quot;VeryGood&quot;}, 
        {&quot;name&quot;:&quot;William&quot;,&quot;Percentage&quot;:36.0,&quot;Remarks&quot;:&quot;Bad&quot;}, 
        {&quot;name&quot;:&quot;Jacob&quot;,&quot;Percentage&quot;:63.0,&quot;Remarks&quot;:&quot;Average&quot;}, 
        {&quot;name&quot;:&quot;Wilson&quot;,&quot;Percentage&quot;:69.3,&quot;Remarks&quot;:&quot;Average&quot;}, 
        {&quot;name&quot;:&quot;Kurtson&quot;,&quot;Percentage&quot;:16.9,&quot;Remarks&quot;:&quot;VeryBad&quot;}, 
        {&quot;name&quot;:&quot;Tom&quot;,&quot;Percentage&quot;:86.3,&quot;Remarks&quot;:&quot;Good&quot;}]

3. Extract Name &amp; Percentage fields &amp; save in a csv

Here is my snippet of the code that is responsible for printing and saving the results


    package main
    
    import (
        &quot;encoding/csv&quot;
        &quot;fmt&quot;
        &quot;net/http&quot;
        &quot;os&quot;
        &quot;strings&quot;
        &quot;encoding/json&quot;
    
    )
    
    
    type Key struct {
    	fname      string
    	marks      int
    	rollno     int
    	}
    
    type object struct {
        Percentage float64
        Name string `json:&quot;name&quot;`
        }
    
     
    func PageRequest(w http.ResponseWriter, r *http.Request) {
       
    
        // Page header
        fmt.Fprintf(w, PageHeader, pages, previous, next)
    
        // Save in csv
        csvfile, err := os.OpenFile(&quot;marks.csv&quot;, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
        if err != nil {
            fmt.Println(&quot;Error:&quot;, err)
            return
        }
        defer csvfile.Close()
    
        writer := csv.NewWriter(csvfile)
        defer writer.Flush()
    
        // Defining RollNos
        var rollNos []string
    
        // Marks for UID
        UID, length := compute(start)
        for i := 0; i &lt; length; i++ {
            key := UID[i]

        // Prints firstname, Marks and Rollno
            fmt.Fprintf(w, key.fname, key.marks, key.rollno) 
    
    
    
            records := [][]string{{key.fname, key.marks, key.rollno}}
    
            for _, record := range records {
                err := writer.Write(record)
                if err != nil {
                    fmt.Println(&quot;Error:&quot;, err)
                    return
                }
            }
    
        // Append All key.rollno
            rollNos := append(rollNos, key.rollno)

        // Makes a request to as studentsapimarks.com/api/rollno1,rollno2,rollno3/detail
            uri := &quot;https://studentsapimarks.com/api/&quot; + strings.Join(rollNos, &quot;,&quot;) + &quot;/detail&quot;

            res, err := http.Get(uri)
            if err != nil {
                log.Fatal(err)
            }
            defer res.Body.Close()
            
            var s []object
            err = json.NewDecoder(res.Body).Decode(&amp;s)
            if err != nil {
                log.Fatal(err)
            }

        // Prints Name/ Percentage
            fmt.Println(s[0].Name)
            fmt.Println(s[0].Percentage)
        }
    
        // Page Footer
        fmt.Fprintf(w, PageFooter, previous, next)
    }
    
    
    func main() {
        http.HandleFunc(&quot;/&quot;, PageRequest)
    
    log.Println(&quot;Listening&quot;)
    log.Fatal(http.ListenAndServe(&quot;:8080&quot;, nil))
    
    }


`fmt.Fprintf(w, key.fname, key.marks, key.rollno)` is working fine and displays all 10 results per page and saves in a csv .

Problem with the code is

1. It is not appending all `key.rollno` that we got in step1 as `studentsapimarks.com/api/rollno1,rollno2,rollno3/detail` 

2. Also how could i save the JSON extracted `s[0].name` results in a CSV ?

</details>


# 答案1
**得分**: 1

JSON解析失败是因为你试图将一个JSON数组解组成一个结构体你想要将JSON数组解组成一个切片 - 外部结构体是不必要的

```go
var s []object
err = json.NewDecoder(res.Body).Decode(&s)

此外,它只能解组导出字段(以大写字母开头的字段),所以要获取名称,你需要更改结构体定义。我猜测百分比也没有传递过来,因为在JSON中它是一个单个的浮点数值,但在你的结构体中你使用了一个浮点数切片。

type object struct {
    // "Percentage": 96.4 不是一个切片。
    // 另外,如果Go和JSON中的字段名相同,你不需要json标签。
    Percentage float64
    // 字段必须大写,标签可以保持小写
    Name string `json:"name"`
}

然后你可以相应地访问这些字段:

// 打印名称/百分比
fmt.Println(s[0].Name)
fmt.Println(s[0].Percentage)
英文:

The JSON parsing is failing because you're trying to unmarshal a JSON array into a struct. You want to unmarshal a JSON array into a slice - the outer struct is not necessary:

var s []object
err = json.NewDecoder(res.Body).Decode(&amp;s)

Also, it can only unmarshal exported fields (those that start with a capital letter), so to get the name, you'll need to change your struct definition. I'm guessing the percentage isn't coming through either, since in the JSON it's a single float value, but in your struct you're taking a float slice.

type object struct {
// &quot;Percentage&quot;: 96.4 is not a slice.
// Also if the field name in Go and JSON are identical, you dont need the json tag.
Percentage float64
// The field must be capitalized, the tag can stay lowercase
Name string `json:&quot;name&quot;`
}

Then you'll access those fields accordingly:

// Prints Name/ Percentage
fmt.Println(s[0].Name)
fmt.Println(s[0].Percentage)

huangapple
  • 本文由 发表于 2017年7月7日 23:11:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/44974200.html
匿名

发表评论

匿名网友

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

确定