Go中查找并删除嵌套的json对象

我有一个 Kubernetes Pod 的 json 文档,这是一个示例: https: //github.com/itaysk/kubectl-neat/blob/master/test/fixtures/pod-1-raw.json

我想遍历spec.containers[i].volumeMounts并删除那些.name"default-token-". 请注意, 和containers都是volumeMounts数组。

使用 jq 我花了 1 分钟写了这 1 行:try del(.spec.containers[].volumeMounts[] | select(.name | startswith("default-token-")))。我正在尝试用 Go 重写它。

在寻找一个好的 json 库时,我选择了 gjson/sjson。由于sjson 不支持数组访问器(#语法),并且 gjson 不支持获取结果路径,因此我寻找解决方法。
我尝试过使用Result.Indexdo delete 直接从字节切片中删除结果,并成功了,但是对于我编写的查询 ( spec.containers.#.volumeMounts.#(name%\"default-token-*\")|0),索引始终为 0 (我尝试了它的不同变体,结果相同)。
所以目前我有一些 25 行代码,它们使用 gjson 来获取spec.containers.#.volumeMounts和迭代它的结构并最终用于sjson.Delete删除。它有效,但感觉比我预期的要复杂得多。

在 Go 中是否有更好的方法来做到这一点?如果需要的话我愿意切换 json 库。

编辑:我宁愿避免使用类型化模式,因为我可能需要在不同类型上执行此操作,对于某些类型我没有完整的模式。
(还删除了有关我当前实现的一些分散注意力的细节)


慕容森
浏览 146回答 2
2回答

12345678_0001

这里最简单的事情是将 JSON 解析为一个对象,使用该对象,然后序列化回 JSON。Kubernetes 提供了一个 Go 客户端库,它定义了v1.Pod 结构,您可以使用 stdlib 编码/json 对其进行解组:// import "k8s.io/api/core/v1"var pod v1.Podif err := json.Unmarshal(podBody, &pod); err != nil {    log.Fatalf("parsing pod json: %s", err)}从那里您可以阅读pod.Spec.Containers和他们的VolumeMounts:// Modify.for c := range pod.Spec.Containers {    container := &pod.Spec.Containers[c]    for i, vol := range container.VolumeMounts {        if strings.HasPrefix(vol.Name, "default-token-") {            // Remove the VolumeMount at index i.            container.VolumeMounts = append(container.VolumeMounts[:i], container.VolumeMounts[i+1:]...)        }    }}https://play.golang.org/p/3r5-XKIazhK如果您担心丢失输入中可能出现的某些任意 JSON,您可能希望定义as 中的每个属性,var pod map[string]interface{}然后进行类型转换,依此类推。spec, ok := pod["spec"].(map[string]interface{})containers, ok := spec["containers"].([]map[string]interface)

慕容3067478

要采取与以前完全不同的方法,您可以创建一个type Root struct {    fields struct {        Spec *Spec `json:"spec,omitempty"`    }    other map[string]interface{}}使用自定义 UnmarshalJSON 解组到字段和其他字段,以及自定义 MarshalJSON 在返回 json.Marshal(other) 之前设置 other["spec"] = json.RawMessage(spec.MarshalJSON()) :func (v *Root) UnmarshalJSON(b []byte) error {    if err := json.Unmarshal(b, &v.fields); err != nil {        return err    }    if v.other == nil {        v.other = make(map[string]interface{})    }    if err := json.Unmarshal(b, &v.other); err != nil {        return err    }    return nil}func (v *Root) MarshalJSON() ([]byte, error) {    var err error    if v.other["spec"], err = rawMarshal(v.fields.Spec); err != nil {        return nil, err    }    return json.Marshal(v.other)}func rawMarshal(v interface{}) (json.RawMessage, error) {    b, err := json.Marshal(v)    if err != nil {        return nil, err    }    return json.RawMessage(b), nil}然后,您可以通过 .spec.containers.volumeMounts 一直定义这些类型,并拥有一个 Container.MarshalJSON ,它会丢弃我们不喜欢的 VolumeMounts:func (v *Container) MarshalJSON() ([]byte, error) {    mounts := v.fields.VolumeMounts    for i, mount := range mounts {        if strings.HasPrefix(mount.fields.Name, "default-token-") {            mounts = append(mounts[:i], mounts[i+1:]...)        }    }    var err error    if v.other["volumeMounts"], err = rawMarshal(mounts); err != nil {        return nil, err    }    return json.Marshal(v.other)}完整的游乐场示例:https ://play.golang.org/p/k1603cchwC7我不会这样做。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go