Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
89cfda8545 | ||
|
24c816c640 | ||
|
a9054b9704 | ||
|
414d979931 |
220
main_test.go
220
main_test.go
|
@ -1,97 +1,205 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type Type int
|
||||
// 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 (
|
||||
TypeChild Type = iota
|
||||
TypeChildren
|
||||
TypeAllChildren
|
||||
SelUnknown Selection = iota
|
||||
SelRoot // 根节点
|
||||
SelSelf // 自身
|
||||
SelParent // 父节点
|
||||
SelChildren // 孩子
|
||||
SelAllChildRen // 所有子孙
|
||||
SelMethod // 函数类型
|
||||
SelAttribute // 属性
|
||||
)
|
||||
|
||||
type Node struct {
|
||||
Prev *Node
|
||||
Next *Node
|
||||
type Predicates struct {
|
||||
Name []rune
|
||||
Type Type
|
||||
}
|
||||
|
||||
// func extractPath(cur *Node) string {
|
||||
// var path []byte
|
||||
|
||||
// if cur.Next.Next == nil {
|
||||
// return "/"
|
||||
// }
|
||||
|
||||
// for ; cur != nil; cur = cur.Next {
|
||||
// path = append(path, cur.Name...)
|
||||
// if cur.Next.Next == nil {
|
||||
// break
|
||||
// }
|
||||
// path = append(path, '/')
|
||||
// }
|
||||
// return string(path)
|
||||
// }
|
||||
|
||||
func toString(root *Node) string {
|
||||
var content string
|
||||
|
||||
for root != nil {
|
||||
|
||||
content += string(root.Name)
|
||||
if root.Type == TypeAllChildren {
|
||||
content += "//"
|
||||
} else {
|
||||
content += "/"
|
||||
}
|
||||
root = root.Next
|
||||
type Node struct {
|
||||
Name []rune // Axis
|
||||
Value []rune // Name(Axis)::Value
|
||||
Next *Node
|
||||
Sel Selection
|
||||
Pred []*Predicates
|
||||
}
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
func xPath(spath string) string {
|
||||
|
||||
var path []rune = []rune(spath)
|
||||
// compile 编译
|
||||
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] == '/' {
|
||||
cur.Type = TypeAllChildren
|
||||
i++
|
||||
head.Sel = SelAllChildRen
|
||||
} else {
|
||||
cur.Type = TypeChild
|
||||
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
|
||||
}
|
||||
|
||||
if len(cur.Name) == 0 {
|
||||
continue
|
||||
return head, cur
|
||||
}
|
||||
|
||||
cur.Next = &Node{Prev: cur}
|
||||
cur = cur.Next
|
||||
// case '(': 先拿括号
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(compile("/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//././/.."))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user