3b807845 by astaxie

beego:addtree support regexp

1 parent 00b710e1
...@@ -28,21 +28,96 @@ func NewTree() *Tree { ...@@ -28,21 +28,96 @@ func NewTree() *Tree {
28 // add Tree to the exist Tree 28 // add Tree to the exist Tree
29 // prefix should has no params 29 // prefix should has no params
30 func (t *Tree) AddTree(prefix string, tree *Tree) { 30 func (t *Tree) AddTree(prefix string, tree *Tree) {
31 t.addtree(splitPath(prefix), tree) 31 t.addtree(splitPath(prefix), tree, nil, "")
32 } 32 }
33 33
34 func (t *Tree) addtree(segments []string, tree *Tree) { 34 func (t *Tree) addtree(segments []string, tree *Tree, wildcards []string, reg string) {
35 if len(segments) == 0 { 35 if len(segments) == 0 {
36 panic("prefix should has path") 36 panic("prefix should has path")
37 } 37 }
38 if len(segments) == 1 && segments[0] != "" { 38 seg := segments[0]
39 t.fixrouters[segments[0]] = tree 39 iswild, params, regexpStr := splitSegment(seg)
40 if len(segments) == 1 && seg != "" {
41 if iswild {
42 wildcards = append(wildcards, params...)
43 if regexpStr != "" {
44 for _, w := range params {
45 if w == "." || w == ":" {
46 continue
47 }
48 regexpStr = "([^/]+)/" + regexpStr
49 }
50 }
51 reg = reg + regexpStr
52 filterTreeWithPrefix(tree, wildcards, reg)
53 t.wildcard = tree
54 } else {
55 filterTreeWithPrefix(tree, wildcards, reg)
56 t.fixrouters[seg] = tree
57 }
40 return 58 return
41 } 59 }
42 seg := segments[0] 60 if iswild {
61 if t.wildcard == nil {
62 t.wildcard = NewTree()
63 }
64 wildcards = append(wildcards)
65 if regexpStr != "" {
66 for _, w := range params {
67 if w == "." || w == ":" {
68 continue
69 }
70 regexpStr = "([^/]+)/" + regexpStr
71 }
72 }
73 reg = reg + regexpStr
74 t.wildcard.addtree(segments[1:], tree, wildcards, reg)
75 } else {
43 subTree := NewTree() 76 subTree := NewTree()
44 t.fixrouters[seg] = subTree 77 t.fixrouters[seg] = subTree
45 subTree.addtree(segments[1:], tree) 78 subTree.addtree(segments[1:], tree, wildcards, reg)
79 }
80 }
81
82 func filterTreeWithPrefix(t *Tree, wildcards []string, reg string) {
83 for _, v := range t.fixrouters {
84 filterTreeWithPrefix(v, wildcards, reg)
85 }
86 if t.wildcard != nil {
87 filterTreeWithPrefix(t.wildcard, wildcards, reg)
88 }
89 if t.leaf != nil {
90 t.leaf.wildcards = append(wildcards, t.leaf.wildcards...)
91 if reg != "" {
92 filterCards := []string{}
93 for _, v := range t.leaf.wildcards {
94 if v == ":" || v == "." {
95 continue
96 }
97 filterCards = append(filterCards, v)
98 }
99 t.leaf.wildcards = filterCards
100 t.leaf.regexps = regexp.MustCompile("^" + reg + strings.Trim(t.leaf.regexps.String(), "^$") + "$")
101 } else {
102 if t.leaf.regexps != nil {
103 filterCards := []string{}
104 for _, v := range t.leaf.wildcards {
105 if v == ":" || v == "." {
106 continue
107 }
108 filterCards = append(filterCards, v)
109 }
110 t.leaf.wildcards = filterCards
111 for _, w := range wildcards {
112 if w == "." || w == ":" {
113 continue
114 }
115 reg = "([^/]+)/" + reg
116 }
117 t.leaf.regexps = regexp.MustCompile("^" + reg + strings.Trim(t.leaf.regexps.String(), "^$") + "$")
118 }
119 }
120 }
46 } 121 }
47 122
48 // call addseg function 123 // call addseg function
...@@ -74,6 +149,18 @@ func (t *Tree) addseg(segments []string, route interface{}, wildcards []string, ...@@ -74,6 +149,18 @@ func (t *Tree) addseg(segments []string, route interface{}, wildcards []string,
74 if t.wildcard == nil { 149 if t.wildcard == nil {
75 t.wildcard = NewTree() 150 t.wildcard = NewTree()
76 } 151 }
152 if regexpStr != "" {
153 if reg == "" {
154 for _, w := range wildcards {
155 if w == "." || w == ":" {
156 continue
157 }
158 regexpStr = "([^/]+)/" + regexpStr
159 }
160 } else {
161 regexpStr = "/" + regexpStr
162 }
163 }
77 t.wildcard.addseg(segments[1:], route, append(wildcards, params...), reg+regexpStr) 164 t.wildcard.addseg(segments[1:], route, append(wildcards, params...), reg+regexpStr)
78 } else { 165 } else {
79 subTree, ok := t.fixrouters[seg] 166 subTree, ok := t.fixrouters[seg]
...@@ -230,12 +317,11 @@ func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params map[string ...@@ -230,12 +317,11 @@ func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params map[string
230 } 317 }
231 return true, params 318 return true, params
232 } 319 }
233 320 if !leaf.regexps.MatchString(path.Join(wildcardValues...)) {
234 if !leaf.regexps.MatchString(strings.Join(wildcardValues, "")) {
235 return false, nil 321 return false, nil
236 } 322 }
237 params = make(map[string]string) 323 params = make(map[string]string)
238 matches := leaf.regexps.FindStringSubmatch(strings.Join(wildcardValues, "")) 324 matches := leaf.regexps.FindStringSubmatch(path.Join(wildcardValues...))
239 for i, match := range matches[1:] { 325 for i, match := range matches[1:] {
240 params[leaf.wildcards[i]] = match 326 params[leaf.wildcards[i]] = match
241 } 327 }
......
...@@ -31,6 +31,9 @@ func init() { ...@@ -31,6 +31,9 @@ func init() {
31 routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)_:name", "/v1/shop/123_nike", map[string]string{":id": "123", ":name": "nike"}}) 31 routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)_:name", "/v1/shop/123_nike", map[string]string{":id": "123", ":name": "nike"}})
32 routers = append(routers, testinfo{"/v1/shop/:id(.+)_cms.html", "/v1/shop/123_cms.html", map[string]string{":id": "123"}}) 32 routers = append(routers, testinfo{"/v1/shop/:id(.+)_cms.html", "/v1/shop/123_cms.html", map[string]string{":id": "123"}})
33 routers = append(routers, testinfo{"/v1/shop/cms_:id(.+)_:page(.+).html", "/v1/shop/cms_123_1.html", map[string]string{":id": "123", ":page": "1"}}) 33 routers = append(routers, testinfo{"/v1/shop/cms_:id(.+)_:page(.+).html", "/v1/shop/cms_123_1.html", map[string]string{":id": "123", ":page": "1"}})
34 routers = append(routers, testinfo{"/v1/:v/cms/aaa_:id(.+)_:page(.+).html", "/v1/2/cms/aaa_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}})
35 routers = append(routers, testinfo{"/v1/:v/cms_:id(.+)_:page(.+).html", "/v1/2/cms_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}})
36 routers = append(routers, testinfo{"/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", "/v1/2_cms/ttt_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}})
34 } 37 }
35 38
36 func TestTreeRouters(t *testing.T) { 39 func TestTreeRouters(t *testing.T) {
...@@ -53,6 +56,57 @@ func TestTreeRouters(t *testing.T) { ...@@ -53,6 +56,57 @@ func TestTreeRouters(t *testing.T) {
53 } 56 }
54 } 57 }
55 58
59 func TestAddTree(t *testing.T) {
60 tr := NewTree()
61 tr.AddRouter("/shop/:id/account", "astaxie")
62 tr.AddRouter("/shop/:sd/ttt_:id(.+)_:page(.+).html", "astaxie")
63 t1 := NewTree()
64 t1.AddTree("/v1/zl", tr)
65 obj, param := t1.Match("/v1/zl/shop/123/account")
66 if obj == nil || obj.(string) != "astaxie" {
67 t.Fatal("/v1/zl/shop/:id/account can't get obj ")
68 }
69 if param == nil {
70 t.Fatal("get param error")
71 }
72 if param[":id"] != "123" {
73 t.Fatal("get :id param error")
74 }
75 obj, param = t1.Match("/v1/zl/shop/123/ttt_1_12.html")
76 if obj == nil || obj.(string) != "astaxie" {
77 t.Fatal("/v1/zl//shop/:sd/ttt_:id(.+)_:page(.+).html can't get obj ")
78 }
79 if param == nil {
80 t.Fatal("get param error")
81 }
82 if param[":sd"] != "123" || param[":id"] != "1" || param[":page"] != "12" {
83 t.Fatal("get :sd :id :page param error")
84 }
85
86 t2 := NewTree()
87 t2.AddTree("/v1/:shopid", tr)
88 obj, param = t2.Match("/v1/zl/shop/123/account")
89 if obj == nil || obj.(string) != "astaxie" {
90 t.Fatal("/v1/:shopid/shop/:id/account can't get obj ")
91 }
92 if param == nil {
93 t.Fatal("get param error")
94 }
95 if param[":id"] != "123" || param[":shopid"] != "zl" {
96 t.Fatal("get :id :shopid param error")
97 }
98 obj, param = t2.Match("/v1/zl/shop/123/ttt_1_12.html")
99 if obj == nil || obj.(string) != "astaxie" {
100 t.Fatal("/v1/:shopid/shop/:sd/ttt_:id(.+)_:page(.+).html can't get obj ")
101 }
102 if param == nil {
103 t.Fatal("get :shopid param error")
104 }
105 if param[":sd"] != "123" || param[":id"] != "1" || param[":page"] != "12" || param[":shopid"] != "zl" {
106 t.Fatal("get :sd :id :page :shopid param error")
107 }
108 }
109
56 func TestSplitPath(t *testing.T) { 110 func TestSplitPath(t *testing.T) {
57 a := splitPath("/") 111 a := splitPath("/")
58 if len(a) != 0 { 112 if len(a) != 0 {
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!