Golang中如何将字符串输入映射到任意JSON结构

Golang中如何将字符串输入映射到任意JSON结构 Go Playground - Go 编程语言

在我的结构体中,我将 defaultResponse 定义为字符串类型,但后来我想根据一些条件将其映射为不同类型的 JSON 结构。但我无法将 defaultResponse 作为字符串并传递一些字符串值。

6 回复

Go Playground - Go 编程语言

谢谢,它起作用了。

更多关于Golang中如何将字符串输入映射到任意JSON结构的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你好 @Saral_Sharma

游乐场中的代码无法编译。在移除了 body 字符串内的两个反引号后,代码可以编译并产生以下输出:

Hello GO
erro101
invalid character 't' after object key:value pair
2009/11/10 23:00:00 Operation: 
erro102
invalid json body provided for the request

这就是你为此主题所提及的错误信息吗?

感谢您的解释,所以您希望将JSON数据解组到结构体中,但保留部分数据作为字符串。

您能控制输入数据吗?如果将defaultResponse对象的值包装成字符串,它将保持为字符串而不会被进一步解组。

"defaultResponse”: "{\“title\”:\“Buy cheese and bread for breakfast.\”}"

Go Playground

Go Playground - The Go Programming Language

type AddEndpointRequest struct {
Method                  string                  `json:"method"`
Path                    string                  `json:"path"`
ContentType             int                     `json:"contentType"`
DefaultWaitTimeInMillis int64                   `json:"defaultWaitTimeInMillis"`
DefaultStatusCode       int                     `json:"defaultStatusCode"`
DefaultResponse         string                  `json:"defaultResponse"`
Filters                 []EndpointFilterRequest `json:"filters"`
}

我希望将 defaultResponse 属性作为 JSON 字符串传递。

如果我传递这个:"defaultResponse":{"title":"Buy cheese and bread for breakfast."} 会收到错误:json: cannot unmarshal object into Go struct field AddEndpointRequest.defaultResponse of type string 所以,我希望将 defaultResponse 属性作为字符串传递,稍后再将其映射为 JSON 对象,但失败了。

body := `{"method":"GET","path":"/getMMEPicks/","contentType":1,"defaultWaitTimeInMillis":100,"defaultStatusCode":200,"defaultResponse":{"title":"Buy cheese and bread for breakfast."},"filters":[{"headerParams":{"contentType":"application/json","userid":"s0s024v"},"queryParams":{"pagesize":"2000","status":"all"},"pathParams":{"countryCode":"US","store":"2686"},"body":"hello","waitTimeInMillis":100,"statusCode":200,"response":"200"}]}`

我进一步尝试简化查询。 在这里,我想将 DefaultResponse 作为字符串接收,但之后在映射到任何 JSON 结构体之前,验证它是否是有效的 JSON。

包含验证的完整代码可以在这里找到: Go Playground - The Go Programming Language

type AddEndpointRequest struct {
    Method            string `json:"method"`
    ContentType       int    `json:"contentType"`
    DefaultStatusCode int    `json:"defaultStatusCode"`
    DefaultResponse   string `json:"defaultResponse"`
}

我尝试了不同的选项,但都不起作用。

  1. 如果我传入这个:"defaultResponse":{"title":"Buy cheese and bread for breakfast."} 会得到错误:json: cannot unmarshal object into Go struct field AddEndpointRequest.defaultResponse of type string

  2. body := {"method":"GET","contentType":1,"defaultWaitTimeInMillis":100,"defaultStatusCode":200,"defaultResponse":"[{"p":"k"}]"}

    错误:invalid character 'p' after object key:value pair

  3. body := {"method":"GET","contentType":1,"defaultWaitTimeInMillis":100,"defaultStatusCode":200,"defaultResponse":"{“p”:“k”}"} ./prog.go:21:117: syntax error: unexpected { at end of statement

  4. body := {"method":"GET","contentType":1,"defaultWaitTimeInMillis":100,"defaultStatusCode":200,"defaultResponse":"{/"p/":/"k/"}“}Error : ./prog.go:21:130: syntax error: unexpected literal "}” at end of statement

还有更多尝试。

在Golang中处理动态JSON结构时,可以使用json.RawMessageinterface{}来延迟解析。以下是两种实现方式:

方法1:使用json.RawMessage

package main

import (
    "encoding/json"
    "fmt"
)

type Response struct {
    Status   int             `json:"status"`
    Data     json.RawMessage `json:"data"`
    Message  string          `json:"message"`
}

func main() {
    // 示例1:data字段为字符串
    jsonStr1 := `{"status":200,"data":"success","message":"操作成功"}`
    
    // 示例2:data字段为对象
    jsonStr2 := `{"status":200,"data":{"id":1,"name":"test"},"message":"操作成功"}`
    
    // 示例3:data字段为数组
    jsonStr3 := `{"status":200,"data":[1,2,3],"message":"操作成功"}`
    
    var resp Response
    
    // 解析字符串类型的data
    json.Unmarshal([]byte(jsonStr1), &resp)
    fmt.Printf("字符串类型: %s\n", resp.Data)
    
    // 解析对象类型的data
    json.Unmarshal([]byte(jsonStr2), &resp)
    fmt.Printf("对象类型: %s\n", resp.Data)
    
    // 解析数组类型的data
    json.Unmarshal([]byte(jsonStr3), &resp)
    fmt.Printf("数组类型: %s\n", resp.Data)
}

方法2:使用interface{}进行动态解析

package main

import (
    "encoding/json"
    "fmt"
)

type DynamicResponse struct {
    Status  int         `json:"status"`
    Data    interface{} `json:"data"`
    Message string      `json:"message"`
}

func main() {
    jsonInput := `{"status":200,"data":{"user":"john","age":30},"message":"success"}`
    
    var resp DynamicResponse
    json.Unmarshal([]byte(jsonInput), &resp)
    
    // 根据实际类型处理data字段
    switch v := resp.Data.(type) {
    case string:
        fmt.Printf("字符串类型: %s\n", v)
    case map[string]interface{}:
        fmt.Printf("对象类型: %v\n", v)
        // 可以进一步访问具体字段
        if user, ok := v["user"]; ok {
            fmt.Printf("用户名: %s\n", user)
        }
    case []interface{}:
        fmt.Printf("数组类型: %v\n", v)
    default:
        fmt.Printf("未知类型: %v\n", v)
    }
}

方法3:自定义UnmarshalJSON实现

package main

import (
    "encoding/json"
    "fmt"
)

type FlexibleData struct {
    Value interface{}
}

func (f *FlexibleData) UnmarshalJSON(data []byte) error {
    // 先尝试解析为字符串
    var str string
    if err := json.Unmarshal(data, &str); err == nil {
        f.Value = str
        return nil
    }
    
    // 再尝试解析为对象
    var obj map[string]interface{}
    if err := json.Unmarshal(data, &obj); err == nil {
        f.Value = obj
        return nil
    }
    
    // 最后尝试解析为数组
    var arr []interface{}
    if err := json.Unmarshal(data, &arr); err == nil {
        f.Value = arr
        return nil
    }
    
    return json.Unmarshal(data, &f.Value)
}

type CustomResponse struct {
    Status  int          `json:"status"`
    Data    FlexibleData `json:"data"`
    Message string       `json:"message"`
}

func main() {
    inputs := []string{
        `{"status":200,"data":"string value","message":"ok"}`,
        `{"status":200,"data":{"key":"value"},"message":"ok"}`,
        `{"status":200,"data":[1,2,3],"message":"ok"}`,
    }
    
    for _, input := range inputs {
        var resp CustomResponse
        json.Unmarshal([]byte(input), &resp)
        fmt.Printf("解析结果: %T %v\n", resp.Data.Value, resp.Data.Value)
    }
}

实际应用示例

package main

import (
    "encoding/json"
    "fmt"
)

type APIResponse struct {
    Success bool            `json:"success"`
    Code    int             `json:"code"`
    Result  json.RawMessage `json:"result"`
    Error   string          `json:"error,omitempty"`
}

// 定义可能的数据结构
type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

type Product struct {
    ID    int     `json:"id"`
    Price float64 `json:"price"`
}

func main() {
    // 模拟API返回的不同类型数据
    responses := []string{
        // 用户数据
        `{"success":true,"code":200,"result":{"id":1,"name":"Alice"}}`,
        // 产品数据
        `{"success":true,"code":200,"result":{"id":101,"price":29.99}}`,
        // 字符串消息
        `{"success":true,"code":200,"result":"操作成功"}`,
        // 数组数据
        `{"success":true,"code":200,"result":[1,2,3,4,5]}`,
    }
    
    for _, respStr := range responses {
        var apiResp APIResponse
        json.Unmarshal([]byte(respStr), &apiResp)
        
        // 根据业务逻辑决定如何解析result
        if len(apiResp.Result) > 0 && apiResp.Result[0] == '{' {
            // 尝试解析为User
            var user User
            if err := json.Unmarshal(apiResp.Result, &user); err == nil && user.ID > 0 {
                fmt.Printf("用户数据: %+v\n", user)
                continue
            }
            
            // 尝试解析为Product
            var product Product
            if err := json.Unmarshal(apiResp.Result, &product); err == nil && product.ID > 0 {
                fmt.Printf("产品数据: %+v\n", product)
                continue
            }
        }
        
        // 其他情况直接输出原始JSON
        fmt.Printf("原始数据: %s\n", apiResp.Result)
    }
}

这些方法允许你在保持类型安全的同时,灵活处理不同结构的JSON数据。json.RawMessage在需要延迟解析或根据条件解析时特别有用,而interface{}提供了最大的灵活性但需要类型断言。

回到顶部