200 lines
3.3 KiB
Go
200 lines
3.3 KiB
Go
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 getAxes(path []rune, limit int, ii *int, cur *Node) {
|
|
i := *ii
|
|
|
|
for ; i < limit; i++ {
|
|
c := path[i]
|
|
switch c {
|
|
case '[':
|
|
case '/':
|
|
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//././/.."))
|
|
}
|