douqian1296 2019-03-06 17:50
浏览 179

json解析后如何列出未知字段

Imagine we have following Go structs:

type Config struct {
    Name   string  `json:"name,omitempty"`
    Params []Param `json:"params,omitempty"`
}

type Param struct {
    Name  string `json:"name,omitempty"`
    Value string `json:"value,omitempty"`
}

and following json:

{
    "name": "parabolic",
    "subdir": "pb",
    "params": [{
        "name": "input",
        "value": "in.csv"
    }, {
        "name": "output",
        "value": "out.csv",
        "tune": "fine"
    }]
}

and we do unmarshalling:

cfg := Config{}
if err := json.Unmarshal([]byte(cfgString), &cfg); err != nil {
    log.Fatalf("Error unmarshalling json: %v", err)
}
fmt.Println(cfg)

https://play.golang.org/p/HZgo0jxbQrp

Output would be {parabolic [{input in.csv} {output out.csv}]} which makes sense - unknown fields were ignored.

Question: how to find out which fields were ignored?

I.e. getIgnoredFields(cfg, cfgString) would return ["subdir", "params[1].tune"]

(There is a DisallowUnknownFields option but it's different: this option would result Unmarshal in error while question is how to still parse json without errors and find out which fields were ignored)

  • 写回答

1条回答 默认 最新

  • douaoj0994 2019-03-13 08:37
    关注

    Not sure if that is the best way but what I did is:

    1. If current-level type is map:

      1. Check that all map keys are known.
        • It could be either if keys are struct field names or map keys.
        • If not known - add to list of unknown fields
      2. Repeat recursively for value that corresponds to each key
    2. If current level type is array:

      1. Run recursively for each element

    Code:

    // ValidateUnknownFields checks that provided json
    // matches provided struct. If that is not the case
    // list of unknown fields is returned.
    func ValidateUnknownFields(jsn []byte, strct interface{}) ([]string, error) {
        var obj interface{}
        err := json.Unmarshal(jsn, &obj)
        if err != nil {
            return nil, fmt.Errorf("error while unmarshaling json: %v", err)
        }
        return checkUnknownFields("", obj, reflect.ValueOf(strct)), nil
    }
    
    func checkUnknownFields(keyPref string, jsn interface{}, strct reflect.Value) []string {
        var uf []string
        switch concreteVal := jsn.(type) {
        case map[string]interface{}:
            // Iterate over map and check every value
            for field, val := range concreteVal {
                fullKey := fmt.Sprintf("%s.%s", keyPref, field)
                subStrct := getSubStruct(field, strct)
                if !subStrct.IsValid() {
                    uf = append(uf, fullKey[1:])
                } else {
                    subUf := checkUnknownFields(fullKey, val, subStrct)
                    uf = append(uf, subUf...)
                }
            }
        case []interface{}:
            for i, val := range concreteVal {
                fullKey := fmt.Sprintf("%s[%v]", keyPref, i)
                subStrct := strct.Index(i)
                uf = append(uf, checkUnknownFields(fullKey, val, subStrct)...)
            }
        }
        return uf
    }
    

    Full version: https://github.com/yb172/json-unknown/blob/master/validator.go

    评论

报告相同问题?

悬赏问题

  • ¥15 uniapp连接阿里云无法发布消息和订阅
  • ¥25 麦当劳点餐系统代码纠错
  • ¥15 轮班监督委员会问题。
  • ¥15 基于作物生长模型下,有限水资源的最大化粮食产量的资源优化模型建立
  • ¥20 关于变压器的具体案例分析
  • ¥15 生成的QRCode圖片加上下載按鈕
  • ¥15 板材切割优化算法,数学建模,python,lingo
  • ¥15 科来模拟ARP欺骗困惑求解
  • ¥100 iOS开发关于快捷指令截屏后如何将截屏(或从截屏中提取出的文本)回传给本应用并打开指定页面
  • ¥15 unity连接Sqlserver