package main import ( "strings" "testing" ) // type Type int // const ( // TypeUnknown Type = iota // TypeNode // TypeText // TypeAttribute // ) // // type Attribute struct { // // Name []rune // // Value []rune // // } // type Node struct { // Parent *Node // Children []*Node // Attributes []*Node // Name []rune // Value []rune // Type Type // } type Selection int const ( SelUnknown Selection = iota SelRoot // 根节点 SelSelf // 自身 SelParent // 父节点 SelChildren // 孩子 SelAllChildRen // 所有子孙 SelMethod // 函数类型 SelAttribute // 属性 ) type Predicates struct { Name []rune } type Node struct { Name []rune // Axis Value []rune // Name(Axis)::Value Next *Node Sel Selection Pred []*Predicates } // compile 编译 func compile(spath string) (head *Node, tail *Node) { var path []rune = []rune(strings.TrimSpace(spath)) path = append(path, ' ') var cur *Node if path[0] == '/' { head = &Node{} head.Sel = SelRoot head.Next = cur } else { head = cur } // 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 getPredicates(path []rune, limit int, ii *int, cur *Node) []*Predicates { return nil } func getAxes(path []rune, limit int, ii *int, cur *Node) { i := *ii for ; i < limit; i++ { c := path[i] switch c { case '[': cur.Pred = getPredicates(path, limit, ii, cur) return case '/': return case ':': if path[i+1] == ':' { i++ return } panic("':' error") case '@': // cur.Sel = SelAttribute cur.Name = getAttributeName(path, limit, ii) case '.': // 获取节点 if path[i+1] == '.' { i++ cur.Sel = SelParent } else { cur.Sel = SelSelf } return case '(': // function s, e := getBrackets(path, limit, ii) cur.Value = path[s:e] cur.Sel = SelMethod return case '\\': // 转义 i++ fallthrough default: cur.Name = append(cur.Name, c) } } } 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/d//././/..")) }