Go 如何将复杂的JSON映射到其他JSON

Go 如何将复杂的JSON映射到其他JSON,go,Go,我正在尝试为我使用的所有第三方API构建聚合服务, 这个聚合服务接受来自我的主系统的json值,它将把这个值放到与第三方api密钥等价的密钥中,然后,聚合服务它将以新的json格式向第三方api发送请求 示例1: package main import ( "encoding/json" "fmt" "log" "github.com/tidwall/gjson" ) func

我正在尝试为我使用的所有第三方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"
}
panic: interface conversion: interface {} is map[string]interface {}, not string
我使用包从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))
}
输出:

{
  "clientName": "xxx",
  "date": "2017-05-17T08:52:36.024Z"
}
panic: interface conversion: interface {} is map[string]interface {}, not string
我可以通过使用来处理这个错误,但是如果这个json对象有数组,而数组中有json对象呢

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

有没有办法映射复杂的json模式或golang包来帮助我实现这一点?

编辑:

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 : 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",
}
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"
}
`
评论互动后,与更新后的问题。在我们向前迈进之前,我想提一提

我刚才看了你的
示例2
记住一件事。映射是从一种形式映射到另一种形式。基本上,
将一种已知格式转换为目标格式
。必须处理每种数据类型。您不能在逻辑上进行
generic
generic
的映射(虽然在技术上可行,但需要花费更多的时间和精力,您可以在这方面进行尝试)

我创建了一种方法的示例工作程序;它将源代码映射到目标格式。把这个计划作为一个起点,运用你的创造力来实施你的计划

游乐场连接:

说明:示例程序将两种不同的源格式转换为一种目标格式。该计划包括-

  • 提供程序1的目标映射定义
  • 提供程序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 : 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",
}
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"
}
`
输出:

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模式

这适用于每个
聚合
系统


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

// get the mapping info by provider
mapping := jsonMappingByProvider["provider1"]

// Parse the response JSON 
// Do the mapping
例如:这是一种方法,请按照您认为合适的方式进行设计

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

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 : 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",
}
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结构的映射:

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 : 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",
}
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

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

非常感谢您的回答,但我的问题是映射,正如您所知,golang强类型,因为我遇到了很多问题,我正在尝试为这个或golang包找到解决方案,以帮助我映射json。谢谢,你能描述一下你面对的问题吗?所以我可以提供我的输入。我已经更新了答案,看一看。我相信这会给你一个开始的想法,然后你可以接受答案。非常感谢你的帮助和你的时间。