【问题标题】:golang Template json to yml formatgolang 模板 json 转 yaml 格式
【发布时间】:2022-01-18 23:11:42
【问题描述】:

您好,我希望使用传递给我们的 go api 的 Json 数据以以下格式创建 Yml。

zookeeper:
  configs:
  
    zookeeper_user: custom-user
    zookeeper_group: custom-group
      
    zookeeper_copy_files:
       - source_path: /path/to/file.txt
         destination_path: /tmp/file.txt

    zookeeper_Some_otherfile:
       - source_path: /path/to/file.txt
         destination_path: /tmp/file.txt
  hosts:
    ip-172-31-34-246.us-east-2.compute.internal:
      zookeeper_id: 2
    ip-172-31-37-15.us-east-2.compute.internal:
      zookeeper_id: 3
    ip-172-31-34-231.us-east-2.compute.internal:
      zookeeper_id: 1


      # zookeeper:
      #   properties:
      #     initLimit: 6
      #     syncLimit: 3
      # zookeeper_server:
      #   properties:
      #     num.io: 15
      # zookeeper_registry:
      #   properties:
      #     key: val
      # Zookeeper_center:
      #   properties:
      #     key: val

使用以下结构解组 json 数据

type Service struct {
    Name string `json:"name"`
    Hosts []Host `json:"hosts"`
    Configs  map[string]interface{} `json:"configs"` 

}

type Host struct {
    HostName         string                 `json:"host_name"`
    CustomHostConfig map[string]interface{} `json:"config"`
}
{{ range $s := $.Services }}
{{ $s.Name }}:
  {{ range $k,$v := $s.Vars }}{{ $k }}: "{{ $v }}"
  {{ end }}
  hosts:
    {{ range $h := $s.Hosts }}
    {{ $h.HostName }}: {{ range $k,$v := $h.CustomHostConfig }}
       {{ $k }}: "{{ $v }}"
      {{ end }}
{{ end }}{{ end }}

我正在使用上面的模板代码,它可以很好地创建以下代码

zookeeper:
  configs:

    zookeeper_user: custom-user
    zookeeper_group: custom-group


  hosts:
    ip-172-31-34-246.us-east-2.compute.internal:
      zookeeper_id: 2
    ip-172-31-37-15.us-east-2.compute.internal:
      zookeeper_id: 3
    ip-172-31-34-231.us-east-2.compute.internal:
      zookeeper_id: 1

我需要帮助将以下配置部分添加到最终的 yml 文件中,以某种动态方式基于使用 Configs map[string]interface{} json:"configs"` 作为键值 json 的一部分传递的用户输入。具有正确的缩进级别。

   zookeeper_copy_files:
       - source_path: /path/to/file.txt
         destination_path: /tmp/file.txt

    zookeeper_Some_otherfile:
       - source_path: /path/to/file.txt
         destination_path: /tmp/file.txt

      # zookeeper:
      #   properties:
      #     initLimit: 6
      #     syncLimit: 3
      # zookeeper_server:
      #   properties:
      #     num.io: 15
      # zookeeper_registry:
      #   properties:
      #     key: val
      # Zookeeper_center:
      #   properties:
      #     key: val
  

【问题讨论】:

  • 目前还不清楚你想问什么,我认为你提供的信息比你需要的多得多。请提供一个最小示例,说明您想要做什么以及您尝试了什么,以便清楚您的要求。特别是,您经常引用模板,但没有说明您打算如何使用它们。您的初始示例显示了一些 Go 类型,但没有显示您正在使用它做什么。请注意,您可以将 Go 值转储为 YAML 而无需任何模板。
  • 我已经更新了问题,希望现在更清楚。
  • 由于空格的重要性,yaml比json更难模板化。相反,使用 Go 数据结构对数据进行建模,然后使用 yaml.Marshal 将其写为 yaml。这来自一个花费数百小时维护应该是有效的 yaml 或 json 模板的人
  • 除了使用主机名作为键之外,还很难使用生成的 yaml。消费者需要为hosts 实现自定义序列化程序。考虑将其更改为列表。示例:go.dev/play/p/1CEZrOhS_po .

标签: go yaml go-templates


【解决方案1】:

不要使用 go 模板编写 YAML,只需使用 YAML 实现,例如:

package main

import (
    "fmt"

    "gopkg.in/yaml.v3"
)

type Service struct {
    Name    string                 `json:"name"`
    Hosts   []Host                 `json:"hosts"`
    Configs map[string]interface{} `json:"configs"`
}

type Host struct {
    HostName         string                 `json:"host_name"`
    CustomHostConfig map[string]interface{} `json:"config"`
}

var services []Service

// create some sample data similar to what you show
func init() {
    var zk Service
    zk.Name = "zookeeper"
    zk.Configs = map[string]interface{}{
        "zookeeper_user":  "custom-user",
        "zookeeper_group": "custom-group",
    }
    zk.Hosts = []Host{
        {"ip-172-31-34-246.us-east-2.compute.internal",
            map[string]interface{}{
                "zookeeper_id": 2,
            }},
        {"ip-172-31-37-15.us-east-2.compute.internal",
            map[string]interface{}{
                "zookeeper_id": 3,
            }},
    }
    services = []Service{zk}
}

func main() {
    out := make(map[string]interface{})
    for _, service := range services {
        var hosts = make(map[string]interface{})
        for _, host := range service.Hosts {
            hosts[host.HostName] = host.CustomHostConfig
        }
        out[service.Name] = map[string]interface{}{
            "hosts":   hosts,
            "configs": service.Configs,
        }
    }
    bytes, err := yaml.Marshal(out)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(bytes))
}

输出(go playground):

zookeeper:
    configs:
        zookeeper_group: custom-group
        zookeeper_user: custom-user
    hosts:
        ip-172-31-34-246.us-east-2.compute.internal:
            zookeeper_id: 2
        ip-172-31-37-15.us-east-2.compute.internal:
            zookeeper_id: 3

这会立即解决您对深度嵌套数据的任何问题,因为 YAML 只是按原样转储结构。

【讨论】:

  • 谢谢@flyx,如果用户想添加我在示例中提到的其他配置,怎么样。例如`zookeeper_copy_files:`部分。它们的值可以是动态的。
  • @user121080 configs 是map[string]interface{},因此也可以将切片和地图作为内容,试试吧!
  • 。可能错过了我添加值并得到错误的技巧。第 39 行 go.dev/play/p/zNz0o41eDA7
  • @user121080 您需要将整个 YAML 结构作为 go 结构,而不是在字符串中提供部分 YAML 特殊字符,这是行不通的。 fixed version。读取相应结构化的 JSON 即可。
  • 非常感谢@flyx,非常感谢您的澄清
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-25
  • 1970-01-01
  • 1970-01-01
  • 2021-12-04
  • 2018-01-14
  • 2016-02-24
相关资源
最近更新 更多