亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Go中查找并刪除嵌套的json對象

Go中查找并刪除嵌套的json對象

Go
慕容森 2023-07-10 17:18:38
我有一個 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 庫。編輯:我寧愿避免使用類型化模式,因為我可能需要在不同類型上執行此操作,對于某些類型我沒有完整的模式。(還刪除了有關我當前實現的一些分散注意力的細節)
查看完整描述

2 回答

?
12345678_0001

TA貢獻1802條經驗 獲得超5個贊

這里最簡單的事情是將 JSON 解析為一個對象,使用該對象,然后序列化回 JSON。

Kubernetes 提供了一個 Go 客戶端庫,它定義了v1.Pod 結構,您可以使用 stdlib 編碼/json 對其進行解組:

// import "k8s.io/api/core/v1"

var pod v1.Pod

if 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)

查看完整回答
反對 回復 2023-07-10
?
慕容3067478

TA貢獻1773條經驗 獲得超3個贊

要采取與以前完全不同的方法,您可以創建一個


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

我不會這樣做。


查看完整回答
反對 回復 2023-07-10
  • 2 回答
  • 0 關注
  • 202 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號