node.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // Copyright 2014 Alvaro J. Genial. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package form
  5. import (
  6. "net/url"
  7. "strconv"
  8. "strings"
  9. )
  10. type node map[string]interface{}
  11. func (n node) values(d, e rune) url.Values {
  12. vs := url.Values{}
  13. n.merge(d, e, "", &vs)
  14. return vs
  15. }
  16. func (n node) merge(d, e rune, p string, vs *url.Values) {
  17. for k, x := range n {
  18. switch y := x.(type) {
  19. case string:
  20. vs.Add(p+escape(d, e, k), y)
  21. case node:
  22. y.merge(d, e, p+escape(d, e, k)+string(d), vs)
  23. default:
  24. panic("value is neither string nor node")
  25. }
  26. }
  27. }
  28. // TODO: Add tests for implicit indexing.
  29. func parseValues(d, e rune, vs url.Values, canIndexFirstLevelOrdinally bool) node {
  30. // NOTE: Because of the flattening of potentially multiple strings to one key, implicit indexing works:
  31. // i. At the first level; e.g. Foo.Bar=A&Foo.Bar=B becomes 0.Foo.Bar=A&1.Foo.Bar=B
  32. // ii. At the last level; e.g. Foo.Bar._=A&Foo.Bar._=B becomes Foo.Bar.0=A&Foo.Bar.1=B
  33. // TODO: At in-between levels; e.g. Foo._.Bar=A&Foo._.Bar=B becomes Foo.0.Bar=A&Foo.1.Bar=B
  34. // (This last one requires that there only be one placeholder in order for it to be unambiguous.)
  35. m := map[string]string{}
  36. for k, ss := range vs {
  37. indexLastLevelOrdinally := strings.HasSuffix(k, string(d)+implicitKey)
  38. for i, s := range ss {
  39. if canIndexFirstLevelOrdinally {
  40. k = strconv.Itoa(i) + string(d) + k
  41. } else if indexLastLevelOrdinally {
  42. k = strings.TrimSuffix(k, implicitKey) + strconv.Itoa(i)
  43. }
  44. m[k] = s
  45. }
  46. }
  47. n := node{}
  48. for k, s := range m {
  49. n = n.split(d, e, k, s)
  50. }
  51. return n
  52. }
  53. func splitPath(d, e rune, path string) (k, rest string) {
  54. esc := false
  55. for i, r := range path {
  56. switch {
  57. case !esc && r == e:
  58. esc = true
  59. case !esc && r == d:
  60. return unescape(d, e, path[:i]), path[i+1:]
  61. default:
  62. esc = false
  63. }
  64. }
  65. return unescape(d, e, path), ""
  66. }
  67. func (n node) split(d, e rune, path, s string) node {
  68. k, rest := splitPath(d, e, path)
  69. if rest == "" {
  70. return add(n, k, s)
  71. }
  72. if _, ok := n[k]; !ok {
  73. n[k] = node{}
  74. }
  75. c := getNode(n[k])
  76. n[k] = c.split(d, e, rest, s)
  77. return n
  78. }
  79. func add(n node, k, s string) node {
  80. if n == nil {
  81. return node{k: s}
  82. }
  83. if _, ok := n[k]; ok {
  84. panic("key " + k + " already set")
  85. }
  86. n[k] = s
  87. return n
  88. }
  89. func isEmpty(x interface{}) bool {
  90. switch y := x.(type) {
  91. case string:
  92. return y == ""
  93. case node:
  94. if s, ok := y[""].(string); ok {
  95. return s == ""
  96. }
  97. return false
  98. }
  99. panic("value is neither string nor node")
  100. }
  101. func getNode(x interface{}) node {
  102. switch y := x.(type) {
  103. case string:
  104. return node{"": y}
  105. case node:
  106. return y
  107. }
  108. panic("value is neither string nor node")
  109. }
  110. func getString(x interface{}) string {
  111. switch y := x.(type) {
  112. case string:
  113. return y
  114. case node:
  115. if s, ok := y[""].(string); ok {
  116. return s
  117. }
  118. return ""
  119. }
  120. panic("value is neither string nor node")
  121. }
  122. func escape(d, e rune, s string) string {
  123. s = strings.Replace(s, string(e), string(e)+string(e), -1) // Escape the escape (\ => \\)
  124. s = strings.Replace(s, string(d), string(e)+string(d), -1) // Escape the delimiter (. => \.)
  125. return s
  126. }
  127. func unescape(d, e rune, s string) string {
  128. s = strings.Replace(s, string(e)+string(d), string(d), -1) // Unescape the delimiter (\. => .)
  129. s = strings.Replace(s, string(e)+string(e), string(e), -1) // Unescape the escape (\\ => \)
  130. return s
  131. }