@@ -302,6 +302,14 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri
302302 return err
303303 }
304304 }
305+
306+ for key , values := range data {
307+ if strings .Contains (key , "." ) || strings .Contains (key , "[" ) {
308+ if err := bindNestedFormField (val , typ , key , values ); err != nil {
309+ return err
310+ }
311+ }
312+ }
305313 return nil
306314}
307315
@@ -487,3 +495,100 @@ func setMultipartFileHeaderTypes(structField reflect.Value, inputFieldName strin
487495
488496 return result
489497}
498+
499+ func parseFieldPath (key string ) []interface {} {
500+ var parts []interface {}
501+ var buf strings.Builder
502+ for i := 0 ; i < len (key ); i ++ {
503+ ch := key [i ]
504+ switch ch {
505+ case '.' :
506+ if buf .Len () > 0 {
507+ parts = append (parts , buf .String ())
508+ buf .Reset ()
509+ }
510+ case '[' :
511+ if buf .Len () > 0 {
512+ parts = append (parts , buf .String ())
513+ buf .Reset ()
514+ }
515+ j := i + 1
516+ for ; j < len (key ) && key [j ] != ']' ; j ++ {
517+ buf .WriteByte (key [j ])
518+ }
519+ index , _ := strconv .Atoi (buf .String ())
520+ parts = append (parts , index )
521+ buf .Reset ()
522+ i = j
523+ default :
524+ buf .WriteByte (ch )
525+ }
526+ }
527+ if buf .Len () > 0 {
528+ parts = append (parts , buf .String ())
529+ }
530+ return parts
531+ }
532+
533+ func bindNestedFormField (val reflect.Value , typ reflect.Type , key string , values []string ) error {
534+ parts := parseFieldPath (key )
535+ return setValueByParts (val , typ , parts , values [0 ])
536+ }
537+
538+ func setValueByParts (val reflect.Value , typ reflect.Type , parts []interface {}, value string ) error {
539+ if len (parts ) == 0 {
540+ return nil
541+ }
542+ part := parts [0 ]
543+ switch v := part .(type ) {
544+ case string :
545+ fieldIdx := - 1
546+ for i := 0 ; i < typ .NumField (); i ++ {
547+ ft := typ .Field (i )
548+ if ft .Tag .Get ("form" ) == v || strings .EqualFold (ft .Name , v ) {
549+ fieldIdx = i
550+ break
551+ }
552+ }
553+ if fieldIdx == - 1 {
554+ return nil
555+ }
556+ fv := val .Field (fieldIdx )
557+ ft := typ .Field (fieldIdx )
558+ if fv .Kind () == reflect .Ptr {
559+ if fv .IsNil () {
560+ fv .Set (reflect .New (ft .Type .Elem ()))
561+ }
562+ fv = fv .Elem ()
563+ ft .Type = ft .Type .Elem ()
564+ }
565+ if len (parts ) == 1 {
566+ return setWithProperType (fv .Kind (), value , fv )
567+ }
568+ return setValueByParts (fv , ft .Type , parts [1 :], value )
569+ case int :
570+ if val .Kind () != reflect .Slice {
571+ return nil
572+ }
573+ for val .Len () <= v {
574+ val .Set (reflect .Append (val , reflect .Zero (val .Type ().Elem ())))
575+ }
576+ elem := val .Index (v )
577+ elemType := val .Type ().Elem ()
578+
579+ if elemType .Kind () == reflect .Ptr {
580+ if elem .IsNil () {
581+ elem .Set (reflect .New (elemType .Elem ()))
582+ }
583+ elem = elem .Elem ()
584+ elemType = elemType .Elem ()
585+ }
586+
587+ if len (parts ) == 1 {
588+ return setWithProperType (elem .Kind (), value , elem )
589+ }
590+
591+ return setValueByParts (elem , elemType , parts [1 :], value )
592+ }
593+ return nil
594+ }
0 commit comments