【问题标题】:how I can mapping complex JSON to other JSON我如何将复杂的 JSON 映射到其他 JSON
【发布时间】:2017-07-15 02:13:36
【问题描述】:

我正在尝试为我使用的所有第三方 API 构建聚合服务, 此聚合服务从我的主系统获取 json 值,并将此值放入与第三方 api 密钥等效的键,然后,聚合服务它将向第三方发送请求新的json格式的api。

示例-1:

package main

import (
    "encoding/json"
    "fmt"
    "log"

    "github.com/tidwall/gjson"
)

func main() {
    // mapping JSON
    mapB := []byte(`
    {
        "date": "createdAt",
        "clientName": "data.user.name"
    }
    `)

    // from my main system
    dataB := []byte(`
    {
        "createdAt": "2017-05-17T08:52:36.024Z",
        "data": {
            "user": {
                "name": "xxx"
            }
        }
    }
    `)

    mapJSON := make(map[string]interface{})
    dataJSON := make(map[string]interface{})
    newJSON := make(map[string]interface{})

    err := json.Unmarshal(mapB, &mapJSON)
    if err != nil {
        log.Panic(err)
    }

    err = json.Unmarshal(dataB, &dataJSON)
    if err != nil {
        log.Panic(err)
    }

    for i := range mapJSON {
        r := gjson.GetBytes(dataB, mapJSON[i].(string))
        newJSON[i] = r.Value()
    }

    newB, err := json.MarshalIndent(newJSON, "", "  ")
    if err != nil {
        log.Println(err)
    }

    fmt.Println(string(newB))
}

输出:

{
  "clientName": "xxx",
  "date": "2017-05-17T08:52:36.024Z"
}

我使用 gjson 包从 json 文档中以简单的方式从我的主系统请求中获取值。

示例-2:

import (
    "encoding/json"
    "fmt"
    "log"

    "github.com/tidwall/gjson"
)

func main() {
    // mapping JSON
    mapB := []byte(`
    {
        "date": "createdAt",
        "clientName": "data.user.name",
        "server":{
            "google":{
                "date" :"createdAt"
            }
        }
    }
    `)

    // from my main system
    dataB := []byte(`
    {
        "createdAt": "2017-05-17T08:52:36.024Z",
        "data": {
            "user": {
                "name": "xxx"
            }
        }
    }
    `)

    mapJSON := make(map[string]interface{})
    dataJSON := make(map[string]interface{})
    newJSON := make(map[string]interface{})

    err := json.Unmarshal(mapB, &mapJSON)
    if err != nil {
        log.Panic(err)
    }

    err = json.Unmarshal(dataB, &dataJSON)
    if err != nil {
        log.Panic(err)
    }

    for i := range mapJSON {
        r := gjson.GetBytes(dataB, mapJSON[i].(string))
        newJSON[i] = r.Value()
    }

    newB, err := json.MarshalIndent(newJSON, "", "  ")
    if err != nil {
        log.Println(err)
    }

    fmt.Println(string(newB))
}

输出:

panic: interface conversion: interface {} is map[string]interface {}, not string

我可以通过使用https://golang.org/ref/spec#Type_assertions 来处理这个错误,但是如果这个 json 对象有数组并且这个数组里面有 json 对象怎么办......

我的问题是我有不同的 api,每个 api 都有自己的 json 架构,我映射 json 的方式只有在 第三方 api 只有 json 键值,在这个数组 json 对象中没有嵌套的 json 或数组。

有没有办法映射复杂的 json 架构或 golang 包来帮助我做到这一点?

【问题讨论】:

    标签: go


    【解决方案1】:

    编辑:

    评论互动和更新问题后。在我们继续之前,我想提一下。

    我刚刚看了你的example-2 记住一件事。映射是从一种形式到另一种形式。基本上one known format to targeted format。每种数据类型都必须处理。你不能在逻辑上进行 genericgeneric 的映射(虽然技术上可行,但需要更多的时间和精力,你可以试试这个)。

    我创建了一种方法的示例工作程序;它执行源到目标格式的映射。将此计划作为起点,并利用您的创造力来实施您的计划。

    游乐场链接:https://play.golang.org/p/MEk_nGcPjZ

    说明:示例程序实现了两种不同的源格式到一种目标格式。该计划包括 -

    • Provider 1 的目标映射定义
    • Provider 2 的目标映射定义
    • 提供者 1 JSON
    • 提供者 2 JSON
    • 映射函数
    • 目标 JSON 编组

    节目的关键元素:完整节目请参考播放链接。

    type MappingInfo struct {
        TargetKey     string
        SourceKeyPath string
        DataType      string
    }
    

    地图功能:

    func mapIt(mapping []*MappingInfo, parsedResult gjson.Result) map[string]interface{} {
        mappedData := make(map[string]interface{})
        for _, m := range mapping {
            switch m.DataType {
            case "time":
                mappedData[m.TargetKey] = parsedResult.Get(m.SourceKeyPath).Time()
            case "string":
                mappedData[m.TargetKey] = parsedResult.Get(m.SourceKeyPath).String()
            }
        }
        return mappedData
    }
    

    输出:

    Provider 1 Result: map[date:2017-05-17 08:52:36.024 +0000 UTC clientName:provider1 username]
    Provider 1 JSON: {
      "clientName": "provider1 username",
      "date": "2017-05-17T08:52:36.024Z"
    }
    
    Provider 2 Result: map[date:2017-05-12 06:32:46.014 +0000 UTC clientName:provider2 username]
    Provider 2 JSON: {
      "clientName": "provider2 username",
      "date": "2017-05-12T06:32:46.014Z"
    }
    

    祝你好运,编码愉快!


    通常将一种结构转换/转换为另一种结构,您必须使用应用程序逻辑来处理。

    正如你在问题中提到的:

    我的问题是我有不同的 api,每个 api 都有自己的 json 架构

    对于每个aggregation 系统都是如此。


    一种有效处理此要求的方法;是保持每个提供者 JSON 结构和目标 JSON 结构的键映射。

    例如:这是一种方法,请按照您认为合适的方式进行设计。

    来自不同提供商的 JSON 结构:

    // Provider 1 : JSON structrure
    {
      "createdAt": "2017-05-17T08:52:36.024Z",
      "data": {
        "user": {
          "name": "xxx"
        }
      }
    }
    
    // Provider 2 : JSON structrure
    {
      "username": "yyy"
      "since": "2017-05-17T08:52:36.024Z",
    }
    

    目标 JSON 结构的映射:

    jsonMappingByProvider := make(map[string]string)
    
    // Targeted Mapping for Provider 1
    jsonMappingByProvider["provider1"] = `
    {
        "date": "createdAt",
        "clientName": "data.user.name"
    }
    `
    
    // Targeted Mapping for Provider 2
    jsonMappingByProvider["provider2"] = `
    {
        "date": "since",
        "clientName": "username"
    }
    `
    

    现在,根据您正在处理的提供者,获取映射并将响应 JSON 映射到目标结构。

    // get the mapping info by provider
    mapping := jsonMappingByProvider["provider1"]
    
    // Parse the response JSON 
    // Do the mapping
    

    通过这种方式,您可以控制每个提供者并有效地进行映射。

    【讨论】:

    • 非常感谢您的回答,但是我的问题是mapping,因为你知道golang强类型,因为很多问题发生在我身上,我正在努力寻找这个或golang包的解决方案来帮助我映射json。
    • 谢谢,您能描述一下您在制图方面遇到的问题吗?这样我就可以提供我的意见。
    • 我已经更新了答案,看看。我相信它会给你一个开始的想法,然后你可以接受答案。
    • 非常感谢您的帮助和您的时间。
    猜你喜欢
    • 2021-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-10
    • 2018-07-28
    相关资源
    最近更新 更多