scan.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. package urlenc
  2. import (
  3. "net/url"
  4. "encoding/json"
  5. "strings"
  6. "fmt"
  7. )
  8. func Unmarshal(bts []byte, v any) error {
  9. unesc, err := url.QueryUnescape(string(bts))
  10. if err != nil {
  11. return err
  12. }
  13. mp := map[string] any{}
  14. err = parseStr(unesc, mp)
  15. if err != nil {
  16. return err
  17. }
  18. js, err := json.Marshal(mp)
  19. if err != nil {
  20. return err
  21. }
  22. err = json.Unmarshal(js, v)
  23. if err != nil {
  24. return err
  25. }
  26. return nil
  27. }
  28. func Marshal(v any) ([]byte, error) {
  29. return nil, nil
  30. }
  31. func parseStr(encodedString string, result map[string]any) error {
  32. // build nested map.
  33. var build func(map[string]any, []string, any) error
  34. build = func(result map[string]any, keys []string, value any) error {
  35. length := len(keys)
  36. // trim ',"
  37. key := strings.Trim(keys[0], "'\"")
  38. if length == 1 {
  39. result[key] = value
  40. return nil
  41. }
  42. // The end is slice. like f[], f[a][]
  43. if keys[1] == "" && length == 2 {
  44. // todo nested slice
  45. if key == "" {
  46. return nil
  47. }
  48. val, ok := result[key]
  49. if !ok {
  50. result[key] = []any{value}
  51. return nil
  52. }
  53. children, ok := val.([]any)
  54. if !ok {
  55. return fmt.Errorf("expected type '[]any' for key '%s', but got '%T'", key, val)
  56. }
  57. result[key] = append(children, value)
  58. return nil
  59. }
  60. // The end is slice + map. like f[][a]
  61. if keys[1] == "" && length > 2 && keys[2] != "" {
  62. val, ok := result[key]
  63. if !ok {
  64. result[key] = []any{}
  65. val = result[key]
  66. }
  67. children, ok := val.([]any)
  68. if !ok {
  69. return fmt.Errorf("expected type '[]any' for key '%s', but got '%T'", key, val)
  70. }
  71. if l := len(children); l > 0 {
  72. if child, ok := children[l-1].(map[string]any); ok {
  73. if _, ok := child[keys[2]]; !ok {
  74. _ = build(child, keys[2:], value)
  75. return nil
  76. }
  77. }
  78. }
  79. child := map[string]any{}
  80. _ = build(child, keys[2:], value)
  81. result[key] = append(children, child)
  82. return nil
  83. }
  84. // map. like f[a], f[a][b]
  85. val, ok := result[key]
  86. if !ok {
  87. result[key] = map[string]any{}
  88. val = result[key]
  89. }
  90. children, ok := val.(map[string]any)
  91. if !ok {
  92. return fmt.Errorf("expected type 'map[string]any' for key '%s', but got '%T'", key, val)
  93. }
  94. return build(children, keys[1:], value)
  95. }
  96. // split encodedString.
  97. parts := strings.Split(encodedString, "&")
  98. for _, part := range parts {
  99. pos := strings.Index(part, "=")
  100. if pos <= 0 {
  101. continue
  102. }
  103. key, err := url.QueryUnescape(part[:pos])
  104. if err != nil {
  105. return err
  106. }
  107. for key[0] == ' ' {
  108. key = key[1:]
  109. }
  110. if key == "" || key[0] == '[' {
  111. continue
  112. }
  113. value, err := url.QueryUnescape(part[pos+1:])
  114. if err != nil {
  115. return err
  116. }
  117. // split into multiple keys
  118. var keys []string
  119. left := 0
  120. for i, k := range key {
  121. if k == '[' && left == 0 {
  122. left = i
  123. } else if k == ']' {
  124. if left > 0 {
  125. if len(keys) == 0 {
  126. keys = append(keys, key[:left])
  127. }
  128. keys = append(keys, key[left+1:i])
  129. left = 0
  130. if i+1 < len(key) && key[i+1] != '[' {
  131. break
  132. }
  133. }
  134. }
  135. }
  136. if len(keys) == 0 {
  137. keys = append(keys, key)
  138. }
  139. // first key
  140. first := ""
  141. for i, chr := range keys[0] {
  142. if chr == ' ' || chr == '.' || chr == '[' {
  143. first += "_"
  144. } else {
  145. first += string(chr)
  146. }
  147. if chr == '[' {
  148. first += keys[0][i+1:]
  149. break
  150. }
  151. }
  152. keys[0] = first
  153. // build nested map
  154. if err := build(result, keys, value); err != nil {
  155. return err
  156. }
  157. }
  158. return nil
  159. }