diff --git a/main_test.go b/main_test.go index faaec26..eef21e3 100644 --- a/main_test.go +++ b/main_test.go @@ -1,97 +1,188 @@ package main import ( + "strings" "testing" ) -type Type int +// type Type int -const ( - TypeChild Type = iota - TypeChildren - TypeAllChildren -) +// const ( +// TypeUnknown Type = iota -type Node struct { - Prev *Node - Next *Node - Name []rune - Type Type -} +// TypeNode +// TypeText +// TypeAttribute +// ) -// func extractPath(cur *Node) string { -// var path []byte +// // type Attribute struct { +// // Name []rune +// // Value []rune +// // } -// if cur.Next.Next == nil { -// return "/" -// } +// type Node struct { +// Parent *Node +// Children []*Node -// for ; cur != nil; cur = cur.Next { -// path = append(path, cur.Name...) -// if cur.Next.Next == nil { -// break -// } -// path = append(path, '/') -// } -// return string(path) +// Attributes []*Node + +// Name []rune +// Value []rune + +// Type Type // } -func toString(root *Node) string { - var content string +type Selection int - for root != nil { +const ( + SelUnknown Selection = iota + SelRoot // 根节点 + SelSelf // 自身 + SelParent // 父节点 + SelChildren // 孩子 + SelAllChildRen // 所有子孙 + SelMethod // 函数类型 + SelAttribute // 属性 +) - content += string(root.Name) - if root.Type == TypeAllChildren { - content += "//" - } else { - content += "/" - } - root = root.Next - } - - return content +type Predicates struct { + Name []rune } -func xPath(spath string) string { +type Node struct { + Name []rune + Value []rune + Next *Node + Sel Selection + Pred Predicates +} - var path []rune = []rune(spath) +func compile(spath string) (head *Node, tail *Node) { + var path []rune = []rune(strings.TrimSpace(spath)) path = append(path, ' ') - root := &Node{} - cur := root + var cur *Node + if path[0] == '/' { + head = &Node{} + head.Sel = SelRoot + head.Next = cur + } else { + head = cur + } - for i := 0; i < len(spath); i++ { + // for i := 0; i < len(spath); i++ { + var i = 0 + c := path[i] + switch c { + case '/': + if path[i+1] == '/' { + i++ + head.Sel = SelAllChildRen + } else { + head.Sel = SelChildren + } + case '.': + head.Sel = SelSelf + case '(': + // 进入递归 + i++ + start, end := getBrackets(path, len(spath), &i) + h, t := compile(string(path[start:end])) + cur.Next = h + cur = t + case '|': + // 递归 + default: + head.Sel = SelUnknown + } + + return head, cur +} + +func getAxes(path []rune, limit int, ii *int, cur *Node) { + i := *ii + + for ; i < limit; i++ { c := path[i] switch c { + case '[': case '/': - if path[i+1] == '/' { - cur.Type = TypeAllChildren + case '@': // + cur.Sel = SelAttribute + cur.Name = getAttributeName(path, limit, ii) + case '.': // 获取节点 + if path[i+1] == '.' { i++ + cur.Sel = SelParent } else { - cur.Type = TypeChild + cur.Sel = SelSelf } - - if len(cur.Name) == 0 { - continue - } - - cur.Next = &Node{Prev: cur} - cur = cur.Next - // case '(': 先拿括号 - + return + case '(': // function + s, e := getBrackets(path, limit, ii) + cur.Value = path[s:e] + cur.Sel = SelMethod + return default: cur.Name = append(cur.Name, c) } } +} - return toString(root) +func getAttributeName(path []rune, limit int, ii *int) []rune { + i := *ii + + for start := i; i < limit; i++ { + if c, ok := Escape(path, &i); !ok { + switch { + case c >= ' ' && c <= '/': + fallthrough + case c >= ':' && c <= '@': + fallthrough + case c >= '[' && c <= '`': + fallthrough + case c >= '{' && c <= '~': + return path[start:i] + default: + panic("get attribute error") + } + } + } + panic("get attribute error") +} + +func getBrackets(path []rune, limit int, ii *int) (start int, end int) { + i := *ii + open := 1 + for start := i; i < limit; i++ { + if c, ok := Escape(path, &i); !ok { + switch c { + case '(': + open++ + case ')': + open-- + } + if open == 0 { + return start, i + } + } + } + panic("can't find ')' close?") +} + +// Escape +func Escape(data []rune, i *int) (rune, bool) { + if data[*i] == '\\' { + *i++ + return data[*i], true + } + return data[*i], false } func TestMain(t *testing.T) { // t.Error(xPath("/a/../../b/../c//.//")) // t.Error(xPath("/a/./b/../../c/")) // t.Error(xPath("/")) - t.Error(xPath("/a/./b/../../c/")) + // t.Error(xPath("/a/./b/../../c/")) // t.Error(xPath("/a//b////c/d//././/..")) }