github.com/gogf/gf@v1.16.9/util/gconv/gconv_map.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package gconv 8 9 import ( 10 "github.com/gogf/gf/internal/json" 11 "reflect" 12 "strings" 13 14 "github.com/gogf/gf/internal/empty" 15 "github.com/gogf/gf/internal/utils" 16 ) 17 18 // Map converts any variable `value` to map[string]interface{}. If the parameter `value` is not a 19 // map/struct/*struct type, then the conversion will fail and returns nil. 20 // 21 // If `value` is a struct/*struct object, the second parameter `tags` specifies the most priority 22 // tags that will be detected, otherwise it detects the tags in order of: 23 // gconv, json, field name. 24 func Map(value interface{}, tags ...string) map[string]interface{} { 25 return doMapConvert(value, false, tags...) 26 } 27 28 // MapDeep does Map function recursively, which means if the attribute of `value` 29 // is also a struct/*struct, calls Map function on this attribute converting it to 30 // a map[string]interface{} type variable. 31 // Also see Map. 32 func MapDeep(value interface{}, tags ...string) map[string]interface{} { 33 return doMapConvert(value, true, tags...) 34 } 35 36 // doMapConvert implements the map converting. 37 // It automatically checks and converts json string to map if `value` is string/[]byte. 38 // 39 // TODO completely implement the recursive converting for all types, especially the map. 40 func doMapConvert(value interface{}, recursive bool, tags ...string) map[string]interface{} { 41 if value == nil { 42 return nil 43 } 44 newTags := StructTagPriority 45 switch len(tags) { 46 case 0: 47 // No need handling. 48 case 1: 49 newTags = append(strings.Split(tags[0], ","), StructTagPriority...) 50 default: 51 newTags = append(tags, StructTagPriority...) 52 } 53 // Assert the common combination of types, and finally it uses reflection. 54 dataMap := make(map[string]interface{}) 55 switch r := value.(type) { 56 case string: 57 // If it is a JSON string, automatically unmarshal it! 58 if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { 59 if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil { 60 return nil 61 } 62 } else { 63 return nil 64 } 65 case []byte: 66 // If it is a JSON string, automatically unmarshal it! 67 if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { 68 if err := json.UnmarshalUseNumber(r, &dataMap); err != nil { 69 return nil 70 } 71 } else { 72 return nil 73 } 74 case map[interface{}]interface{}: 75 for k, v := range r { 76 dataMap[String(k)] = doMapConvertForMapOrStructValue(false, v, recursive, newTags...) 77 } 78 case map[interface{}]string: 79 for k, v := range r { 80 dataMap[String(k)] = v 81 } 82 case map[interface{}]int: 83 for k, v := range r { 84 dataMap[String(k)] = v 85 } 86 case map[interface{}]uint: 87 for k, v := range r { 88 dataMap[String(k)] = v 89 } 90 case map[interface{}]float32: 91 for k, v := range r { 92 dataMap[String(k)] = v 93 } 94 case map[interface{}]float64: 95 for k, v := range r { 96 dataMap[String(k)] = v 97 } 98 case map[string]bool: 99 for k, v := range r { 100 dataMap[k] = v 101 } 102 case map[string]int: 103 for k, v := range r { 104 dataMap[k] = v 105 } 106 case map[string]uint: 107 for k, v := range r { 108 dataMap[k] = v 109 } 110 case map[string]float32: 111 for k, v := range r { 112 dataMap[k] = v 113 } 114 case map[string]float64: 115 for k, v := range r { 116 dataMap[k] = v 117 } 118 case map[string]interface{}: 119 if recursive { 120 // A copy of current map. 121 for k, v := range r { 122 dataMap[k] = doMapConvertForMapOrStructValue(false, v, recursive, newTags...) 123 } 124 } else { 125 // It returns the map directly without any changing. 126 return r 127 } 128 case map[int]interface{}: 129 for k, v := range r { 130 dataMap[String(k)] = doMapConvertForMapOrStructValue(false, v, recursive, newTags...) 131 } 132 case map[int]string: 133 for k, v := range r { 134 dataMap[String(k)] = v 135 } 136 case map[uint]string: 137 for k, v := range r { 138 dataMap[String(k)] = v 139 } 140 141 default: 142 // Not a common type, it then uses reflection for conversion. 143 var reflectValue reflect.Value 144 if v, ok := value.(reflect.Value); ok { 145 reflectValue = v 146 } else { 147 reflectValue = reflect.ValueOf(value) 148 } 149 reflectKind := reflectValue.Kind() 150 // If it is a pointer, we should find its real data type. 151 for reflectKind == reflect.Ptr { 152 reflectValue = reflectValue.Elem() 153 reflectKind = reflectValue.Kind() 154 } 155 switch reflectKind { 156 // If `value` is type of array, it converts the value of even number index as its key and 157 // the value of odd number index as its corresponding value, for example: 158 // []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"} 159 // []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil} 160 case reflect.Slice, reflect.Array: 161 length := reflectValue.Len() 162 for i := 0; i < length; i += 2 { 163 if i+1 < length { 164 dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface() 165 } else { 166 dataMap[String(reflectValue.Index(i).Interface())] = nil 167 } 168 } 169 case reflect.Map, reflect.Struct, reflect.Interface: 170 convertedValue := doMapConvertForMapOrStructValue(true, value, recursive, newTags...) 171 if m, ok := convertedValue.(map[string]interface{}); ok { 172 return m 173 } 174 return nil 175 default: 176 return nil 177 } 178 } 179 return dataMap 180 } 181 182 func doMapConvertForMapOrStructValue(isRoot bool, value interface{}, recursive bool, tags ...string) interface{} { 183 if isRoot == false && recursive == false { 184 return value 185 } 186 var reflectValue reflect.Value 187 if v, ok := value.(reflect.Value); ok { 188 reflectValue = v 189 value = v.Interface() 190 } else { 191 reflectValue = reflect.ValueOf(value) 192 } 193 reflectKind := reflectValue.Kind() 194 // If it is a pointer, we should find its real data type. 195 for reflectKind == reflect.Ptr { 196 reflectValue = reflectValue.Elem() 197 reflectKind = reflectValue.Kind() 198 } 199 switch reflectKind { 200 case reflect.Map: 201 var ( 202 mapKeys = reflectValue.MapKeys() 203 dataMap = make(map[string]interface{}) 204 ) 205 for _, k := range mapKeys { 206 dataMap[String(k.Interface())] = doMapConvertForMapOrStructValue( 207 false, 208 reflectValue.MapIndex(k).Interface(), 209 recursive, 210 tags..., 211 ) 212 } 213 if len(dataMap) == 0 { 214 return value 215 } 216 return dataMap 217 case reflect.Struct: 218 // Map converting interface check. 219 if v, ok := value.(apiMapStrAny); ok { 220 m := v.MapStrAny() 221 if recursive { 222 for k, v := range m { 223 m[k] = doMapConvertForMapOrStructValue(false, v, recursive, tags...) 224 } 225 } 226 return m 227 } 228 // Using reflect for converting. 229 var ( 230 rtField reflect.StructField 231 rvField reflect.Value 232 dataMap = make(map[string]interface{}) // result map. 233 reflectType = reflectValue.Type() // attribute value type. 234 mapKey = "" // mapKey may be the tag name or the struct attribute name. 235 ) 236 for i := 0; i < reflectValue.NumField(); i++ { 237 rtField = reflectType.Field(i) 238 rvField = reflectValue.Field(i) 239 // Only convert the public attributes. 240 fieldName := rtField.Name 241 if !utils.IsLetterUpper(fieldName[0]) { 242 continue 243 } 244 mapKey = "" 245 fieldTag := rtField.Tag 246 for _, tag := range tags { 247 if mapKey = fieldTag.Get(tag); mapKey != "" { 248 break 249 } 250 } 251 if mapKey == "" { 252 mapKey = fieldName 253 } else { 254 // Support json tag feature: -, omitempty 255 mapKey = strings.TrimSpace(mapKey) 256 if mapKey == "-" { 257 continue 258 } 259 array := strings.Split(mapKey, ",") 260 if len(array) > 1 { 261 switch strings.TrimSpace(array[1]) { 262 case "omitempty": 263 if empty.IsEmpty(rvField.Interface()) { 264 continue 265 } else { 266 mapKey = strings.TrimSpace(array[0]) 267 } 268 default: 269 mapKey = strings.TrimSpace(array[0]) 270 } 271 } 272 } 273 if recursive || rtField.Anonymous { 274 // Do map converting recursively. 275 var ( 276 rvAttrField = rvField 277 rvAttrKind = rvField.Kind() 278 ) 279 if rvAttrKind == reflect.Ptr { 280 rvAttrField = rvField.Elem() 281 rvAttrKind = rvAttrField.Kind() 282 } 283 switch rvAttrKind { 284 case reflect.Struct: 285 var ( 286 hasNoTag = mapKey == fieldName 287 rvAttrInterface = rvAttrField.Interface() 288 ) 289 if hasNoTag && rtField.Anonymous { 290 // It means this attribute field has no tag. 291 // Overwrite the attribute with sub-struct attribute fields. 292 anonymousValue := doMapConvertForMapOrStructValue(false, rvAttrInterface, true, tags...) 293 if m, ok := anonymousValue.(map[string]interface{}); ok { 294 for k, v := range m { 295 dataMap[k] = v 296 } 297 } else { 298 dataMap[mapKey] = rvAttrInterface 299 } 300 } else if !hasNoTag && rtField.Anonymous { 301 // It means this attribute field has desired tag. 302 dataMap[mapKey] = doMapConvertForMapOrStructValue(false, rvAttrInterface, true, tags...) 303 } else { 304 dataMap[mapKey] = doMapConvertForMapOrStructValue(false, rvAttrInterface, recursive, tags...) 305 } 306 307 // The struct attribute is type of slice. 308 case reflect.Array, reflect.Slice: 309 length := rvField.Len() 310 if length == 0 { 311 dataMap[mapKey] = rvField.Interface() 312 break 313 } 314 array := make([]interface{}, length) 315 for i := 0; i < length; i++ { 316 array[i] = doMapConvertForMapOrStructValue(false, rvField.Index(i), recursive, tags...) 317 } 318 dataMap[mapKey] = array 319 320 default: 321 if rvField.IsValid() { 322 dataMap[mapKey] = reflectValue.Field(i).Interface() 323 } else { 324 dataMap[mapKey] = nil 325 } 326 } 327 } else { 328 // No recursive map value converting 329 if rvField.IsValid() { 330 dataMap[mapKey] = reflectValue.Field(i).Interface() 331 } else { 332 dataMap[mapKey] = nil 333 } 334 } 335 } 336 if len(dataMap) == 0 { 337 return value 338 } 339 return dataMap 340 341 // The given value is type of slice. 342 case reflect.Array, reflect.Slice: 343 length := reflectValue.Len() 344 if length == 0 { 345 break 346 } 347 array := make([]interface{}, reflectValue.Len()) 348 for i := 0; i < length; i++ { 349 array[i] = doMapConvertForMapOrStructValue(false, reflectValue.Index(i), recursive, tags...) 350 } 351 return array 352 } 353 return value 354 } 355 356 // MapStrStr converts `value` to map[string]string. 357 // Note that there might be data copy for this map type converting. 358 func MapStrStr(value interface{}, tags ...string) map[string]string { 359 if r, ok := value.(map[string]string); ok { 360 return r 361 } 362 m := Map(value, tags...) 363 if len(m) > 0 { 364 vMap := make(map[string]string, len(m)) 365 for k, v := range m { 366 vMap[k] = String(v) 367 } 368 return vMap 369 } 370 return nil 371 } 372 373 // MapStrStrDeep converts `value` to map[string]string recursively. 374 // Note that there might be data copy for this map type converting. 375 func MapStrStrDeep(value interface{}, tags ...string) map[string]string { 376 if r, ok := value.(map[string]string); ok { 377 return r 378 } 379 m := MapDeep(value, tags...) 380 if len(m) > 0 { 381 vMap := make(map[string]string, len(m)) 382 for k, v := range m { 383 vMap[k] = String(v) 384 } 385 return vMap 386 } 387 return nil 388 }