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  }