使用已知的结构体解析具有未知字段名的JSON。

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

Go unmarshal JSON with unknown field name but known struct

问题

我从traefik tls中获取了一个acme.json文件,其中traefik存储了SSL/TLS证书的信息。

现在我想要使用golang将acme.json反序列化到我的go结构体"Traefik"中。但是我不知道如何处理动态/未知的JSON字段名,因为certificateresolver1certificateresolver2是我在编译时不知道的名称。这些名称应该在go中进行动态配置。

我知道JSON的结构(它始终相同),但不知道certificateresolver的字段名。

有人知道如何最好地做到这一点吗?

Traefik acme.json

{
  "certificateresolver1": {
    "Account": {
      "Email": "email@example.com",
      "Registration": {
        "body": {
          "status": "valid",
          "contact": [
            "mailto:email@example.com"
          ]
        },
        "uri": "https://acme-v02.api.letsencrypt.org/acme/acct/124448363"
      },
      "PrivateKey": "PRIVATEKEY",
      "KeyType": "4096"
    },
    "Certificates": [
      {
        "domain": {
          "main": "example.com",
          "sans": [
            "test.example.com"
          ]
        },
        "certificate": "CERTIFICATE",
        "key": "KEY",
        "Store": "default"
      },
      {
        "domain": {
          "main": "example.org"
        },
        "certificate": "CERTIFICATE",
        "key": "KEY",
        "Store": "default"
      }
    ]
  },
  "certificateresolver2": {
    "Account": {
      "Email": "email@example.com",
      "Registration": {
        "body": {
          "status": "valid",
          "contact": [
            "mailto:email@example.com"
          ]
        },
        "uri": "https://acme-v02.api.letsencrypt.org/acme/acct/126945414"
      },
      "PrivateKey": "PRIVATEKEY",
      "KeyType": "4096"
    },
    "Certificates": [
      {
        "domain": {
          "main": "example.net"
        },
        "certificate": "CERTIFICATE",
        "key": "KEY",
        "Store": "default"
      }
    ]
  }
}

acme.json的Go结构体

type Traefik struct {
	Provider []struct {
		Account struct {
			Email        string `json:"Email"`
			Registration struct {
				Body struct {
					Status  string   `json:"status"`
					Contact []string `json:"contact"`
				} `json:"body"`
				URI string `json:"uri"`
			} `json:"Registration"`
			PrivateKey string `json:"PrivateKey"`
			KeyType    string `json:"KeyType"`
		} `json:"Account"`
		Certificates []struct {
			Domain struct {
				Main string   `json:"main"`
				Sans []string `json:"sans"`
			} `json:"domain"`
			Certificate string `json:"certificate"`
			Key         string `json:"key"`
			Store       string `json:"Store"`
		} `json:"Certificates"`
	} `json:"certificateresolver"`  // 在这里写什么?它应该适用于certificateresolver1和certificateresolver2
}
英文:

I retrieve a acme.json from traefik tls where traefik stores ssl/tls certificate information.

Now I want to unmarshal with golang the acme.json into my go struct "Traefik". But I don't know how to handle dynamic/unknown json field names because certificateresolver1 and certificateresolver2 are names I don't know at compile time. These names should be dynamic configured in go.

I know the structure of the json (it is always the same) but not know the field name of the certificateresolver.

Does anyone know the best way to do this?

Traefik acme.json

{
  "certificateresolver1": {
    "Account": {
      "Email": "email@example.com",
      "Registration": {
        "body": {
          "status": "valid",
          "contact": [
            "mailto:email@example.com"
          ]
        },
        "uri": "https://acme-v02.api.letsencrypt.org/acme/acct/124448363"
      },
      "PrivateKey": "PRIVATEKEY",
      "KeyType": "4096"
    },
    "Certificates": [
      {
        "domain": {
          "main": "example.com",
          "sans": [
            "test.example.com"
          ]
        },
        "certificate": "CERTIFICATE",
        "key": "KEY",
        "Store": "default"
      },
      {
        "domain": {
          "main": "example.org"
        },
        "certificate": "CERTIFICATE",
        "key": "KEY",
        "Store": "default"
      }
    ]
  },
  "certificateresolver2": {
    "Account": {
      "Email": "email@example.com",
      "Registration": {
        "body": {
          "status": "valid",
          "contact": [
            "mailto:email@example.com"
          ]
        },
        "uri": "https://acme-v02.api.letsencrypt.org/acme/acct/126945414"
      },
      "PrivateKey": "PRIVATEKEY",
      "KeyType": "4096"
    },
    "Certificates": [
      {
        "domain": {
          "main": "example.net"
        },
        "certificate": "CERTIFICATE",
        "key": "KEY",
        "Store": "default"
      }
    ]
  }
}

Go struct for acme.json

type Traefik struct {
	Provider []struct {
		Account struct {
			Email        string `json:"Email"`
			Registration struct {
				Body struct {
					Status  string   `json:"status"`
					Contact []string `json:"contact"`
				} `json:"body"`
				URI string `json:"uri"`
			} `json:"Registration"`
			PrivateKey string `json:"PrivateKey"`
			KeyType    string `json:"KeyType"`
		} `json:"Account"`
		Certificates []struct {
			Domain struct {
				Main string   `json:"main"`
				Sans []string `json:"sans"`
			} `json:"domain"`
			Certificate string `json:"certificate"`
			Key         string `json:"key"`
			Store       string `json:"Store"`
		} `json:"Certificates"`
	} `json:"certificateresolver"` <-- What to write there? It should fit for certificateresolver1 and certificateresolver2
}

答案1

得分: 3

我认为这样的代码可以帮到你:

type ProviderMdl map[string]Provider

type Provider struct {
	Account struct {
		Email        string `json:"Email"`
		Registration struct {
			Body struct {
				Status  string   `json:"status"`
				Contact []string `json:"contact"`
			} `json:"body"`
			URI string `json:"uri"`
		} `json:"Registration"`
		PrivateKey string `json:"PrivateKey"`
		KeyType    string `json:"KeyType"`
	} `json:"Account"`
	Certificates []struct {
		Domain struct {
			Main string   `json:"main"`
			Sans []string `json:"sans"`
		} `json:"domain"`
		Certificate string `json:"certificate"`
		Key         string `json:"key"`
		Store       string `json:"Store"`
	} `json:"Certificates"`
}

你可以按照以下方式处理这个数据:

bres := new(ProviderMdl)
if err := json.Unmarshal(data, bres); err != nil {
	panic(err)
}

// fmt.Printf("%+v - \n", bres)

for key, value := range *bres {
	fmt.Printf("%v - %v\n", key, value)
}

完整的示例可以在这里找到。

英文:

I think something like this will help you:

type ProviderMdl map[string]Provider

type Provider struct {
	Account struct {
		Email        string `json:"Email"`
		Registration struct {
			Body struct {
				Status  string   `json:"status"`
				Contact []string `json:"contact"`
			} `json:"body"`
			URI string `json:"uri"`
		} `json:"Registration"`
		PrivateKey string `json:"PrivateKey"`
		KeyType    string `json:"KeyType"`
	} `json:"Account"`
	Certificates []struct {
		Domain struct {
			Main string   `json:"main"`
			Sans []string `json:"sans"`
		} `json:"domain"`
		Certificate string `json:"certificate"`
		Key         string `json:"key"`
		Store       string `json:"Store"`
	} `json:"Certificates"`
}

So you could work with this data in this way:

	bres := new(ProviderMdl)
	if err := json.Unmarshal(data, bres); err != nil {
		panic(err)
	}
	
	// fmt.Printf("%+v - \n", bres)

	for key, value := range *bres {
		fmt.Printf("%v - %v\n", key, value)
	}

Full example here

huangapple
  • 本文由 发表于 2021年6月16日 03:10:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/67992166.html
匿名

发表评论

匿名网友

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

确定