2019-02-02 16:18:25 +08:00
|
|
|
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
2018-11-30 09:48:57 +08:00
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
2019-02-02 16:18:25 +08:00
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
2018-11-30 09:48:57 +08:00
|
|
|
|
|
|
|
package gconv
|
|
|
|
|
|
|
|
import (
|
2019-05-28 21:41:00 +08:00
|
|
|
"reflect"
|
|
|
|
"strings"
|
2018-11-30 09:48:57 +08:00
|
|
|
|
2019-07-04 11:11:41 +08:00
|
|
|
"github.com/gogf/gf/g/internal/empty"
|
2019-07-18 18:59:49 +08:00
|
|
|
"github.com/gogf/gf/g/internal/strutils"
|
2019-05-16 13:56:49 +08:00
|
|
|
)
|
2019-05-28 21:41:00 +08:00
|
|
|
|
|
|
|
// Map converts any variable <value> to map[string]interface{}.
|
2019-07-04 11:11:41 +08:00
|
|
|
//
|
|
|
|
// If the parameter <value> is not a map/struct/*struct type, then the conversion will fail and returns nil.
|
|
|
|
//
|
|
|
|
// If <value> is a struct/*struct object, the second parameter <tags> specifies the most priority
|
|
|
|
// tags that will be detected, otherwise it detects the tags in order of: gconv, json, and then the field name.
|
2019-06-19 09:06:52 +08:00
|
|
|
func Map(value interface{}, tags ...string) map[string]interface{} {
|
|
|
|
if value == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if r, ok := value.(map[string]interface{}); ok {
|
|
|
|
return r
|
|
|
|
} else {
|
|
|
|
// Only assert the common combination of types, and finally it uses reflection.
|
|
|
|
m := make(map[string]interface{})
|
|
|
|
switch value.(type) {
|
|
|
|
case map[interface{}]interface{}:
|
|
|
|
for k, v := range value.(map[interface{}]interface{}) {
|
|
|
|
m[String(k)] = v
|
|
|
|
}
|
|
|
|
case map[interface{}]string:
|
|
|
|
for k, v := range value.(map[interface{}]string) {
|
|
|
|
m[String(k)] = v
|
|
|
|
}
|
|
|
|
case map[interface{}]int:
|
|
|
|
for k, v := range value.(map[interface{}]int) {
|
|
|
|
m[String(k)] = v
|
|
|
|
}
|
|
|
|
case map[interface{}]uint:
|
|
|
|
for k, v := range value.(map[interface{}]uint) {
|
|
|
|
m[String(k)] = v
|
|
|
|
}
|
|
|
|
case map[interface{}]float32:
|
|
|
|
for k, v := range value.(map[interface{}]float32) {
|
|
|
|
m[String(k)] = v
|
|
|
|
}
|
|
|
|
case map[interface{}]float64:
|
|
|
|
for k, v := range value.(map[interface{}]float64) {
|
|
|
|
m[String(k)] = v
|
|
|
|
}
|
|
|
|
case map[string]bool:
|
|
|
|
for k, v := range value.(map[string]bool) {
|
|
|
|
m[k] = v
|
|
|
|
}
|
|
|
|
case map[string]int:
|
|
|
|
for k, v := range value.(map[string]int) {
|
|
|
|
m[k] = v
|
|
|
|
}
|
|
|
|
case map[string]uint:
|
|
|
|
for k, v := range value.(map[string]uint) {
|
|
|
|
m[k] = v
|
|
|
|
}
|
|
|
|
case map[string]float32:
|
|
|
|
for k, v := range value.(map[string]float32) {
|
|
|
|
m[k] = v
|
|
|
|
}
|
|
|
|
case map[string]float64:
|
|
|
|
for k, v := range value.(map[string]float64) {
|
|
|
|
m[k] = v
|
|
|
|
}
|
|
|
|
case map[int]interface{}:
|
|
|
|
for k, v := range value.(map[int]interface{}) {
|
|
|
|
m[String(k)] = v
|
|
|
|
}
|
|
|
|
case map[int]string:
|
|
|
|
for k, v := range value.(map[int]string) {
|
|
|
|
m[String(k)] = v
|
|
|
|
}
|
|
|
|
case map[uint]string:
|
|
|
|
for k, v := range value.(map[uint]string) {
|
|
|
|
m[String(k)] = v
|
|
|
|
}
|
|
|
|
// Not a common type, use reflection
|
|
|
|
default:
|
|
|
|
rv := reflect.ValueOf(value)
|
|
|
|
kind := rv.Kind()
|
|
|
|
// If it is a pointer, we should find its real data type.
|
|
|
|
if kind == reflect.Ptr {
|
|
|
|
rv = rv.Elem()
|
|
|
|
kind = rv.Kind()
|
|
|
|
}
|
|
|
|
switch kind {
|
|
|
|
case reflect.Map:
|
|
|
|
ks := rv.MapKeys()
|
|
|
|
for _, k := range ks {
|
|
|
|
m[String(k.Interface())] = rv.MapIndex(k).Interface()
|
|
|
|
}
|
|
|
|
case reflect.Struct:
|
|
|
|
rt := rv.Type()
|
|
|
|
name := ""
|
2019-07-04 11:11:41 +08:00
|
|
|
tagArray := structTagPriority
|
2019-06-19 09:06:52 +08:00
|
|
|
switch len(tags) {
|
|
|
|
case 0:
|
|
|
|
// No need handle.
|
|
|
|
case 1:
|
2019-07-04 14:27:43 +08:00
|
|
|
tagArray = append(strings.Split(tags[0], ","), structTagPriority...)
|
2019-06-19 09:06:52 +08:00
|
|
|
default:
|
2019-07-04 14:27:43 +08:00
|
|
|
tagArray = append(tags, structTagPriority...)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
for i := 0; i < rv.NumField(); i++ {
|
|
|
|
// Only convert the public attributes.
|
|
|
|
fieldName := rt.Field(i).Name
|
2019-07-18 18:59:49 +08:00
|
|
|
if !strutils.IsLetterUpper(fieldName[0]) {
|
2019-06-19 09:06:52 +08:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
name = ""
|
|
|
|
fieldTag := rt.Field(i).Tag
|
|
|
|
for _, tag := range tagArray {
|
|
|
|
if name = fieldTag.Get(tag); name != "" {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if name == "" {
|
|
|
|
name = strings.TrimSpace(fieldName)
|
|
|
|
} else {
|
|
|
|
// Support json tag feature: -, omitempty
|
|
|
|
name = strings.TrimSpace(name)
|
|
|
|
if name == "-" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
array := strings.Split(name, ",")
|
|
|
|
if len(array) > 1 {
|
|
|
|
switch strings.TrimSpace(array[1]) {
|
|
|
|
case "omitempty":
|
|
|
|
if empty.IsEmpty(rv.Field(i).Interface()) {
|
|
|
|
continue
|
|
|
|
} else {
|
|
|
|
name = strings.TrimSpace(array[0])
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
name = strings.TrimSpace(array[0])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m[name] = rv.Field(i).Interface()
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return m
|
|
|
|
}
|
2018-11-30 09:48:57 +08:00
|
|
|
}
|
2019-05-28 21:41:00 +08:00
|
|
|
|
|
|
|
// MapDeep do Map function recursively.
|
|
|
|
// See Map.
|
2019-06-19 09:06:52 +08:00
|
|
|
func MapDeep(value interface{}, tags ...string) map[string]interface{} {
|
2019-05-28 21:41:00 +08:00
|
|
|
data := Map(value, tags...)
|
|
|
|
for key, value := range data {
|
2019-06-19 09:06:52 +08:00
|
|
|
rv := reflect.ValueOf(value)
|
2019-05-28 21:41:00 +08:00
|
|
|
kind := rv.Kind()
|
|
|
|
if kind == reflect.Ptr {
|
2019-06-19 09:06:52 +08:00
|
|
|
rv = rv.Elem()
|
2019-05-28 21:41:00 +08:00
|
|
|
kind = rv.Kind()
|
|
|
|
}
|
|
|
|
switch kind {
|
2019-06-19 09:06:52 +08:00
|
|
|
case reflect.Struct:
|
|
|
|
delete(data, key)
|
|
|
|
for k, v := range MapDeep(value, tags...) {
|
|
|
|
data[k] = v
|
|
|
|
}
|
2019-05-28 21:41:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return data
|
|
|
|
}
|