mirror of
https://github.com/bettercap/bettercap
synced 2025-07-06 13:02:12 -07:00
149 lines
2.8 KiB
Go
149 lines
2.8 KiB
Go
package jsonquery
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/antchfx/xpath"
|
|
)
|
|
|
|
var _ xpath.NodeNavigator = &NodeNavigator{}
|
|
|
|
// CreateXPathNavigator creates a new xpath.NodeNavigator for the specified html.Node.
|
|
func CreateXPathNavigator(top *Node) *NodeNavigator {
|
|
return &NodeNavigator{cur: top, root: top}
|
|
}
|
|
|
|
// Find searches the Node that matches by the specified XPath expr.
|
|
func Find(top *Node, expr string) []*Node {
|
|
exp, err := xpath.Compile(expr)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
t := exp.Select(CreateXPathNavigator(top))
|
|
var elems []*Node
|
|
for t.MoveNext() {
|
|
elems = append(elems, (t.Current().(*NodeNavigator)).cur)
|
|
}
|
|
return elems
|
|
}
|
|
|
|
// FindOne searches the Node that matches by the specified XPath expr,
|
|
// and returns first element of matched.
|
|
func FindOne(top *Node, expr string) *Node {
|
|
exp, err := xpath.Compile(expr)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
t := exp.Select(CreateXPathNavigator(top))
|
|
var elem *Node
|
|
if t.MoveNext() {
|
|
elem = (t.Current().(*NodeNavigator)).cur
|
|
}
|
|
return elem
|
|
}
|
|
|
|
// NodeNavigator is for navigating JSON document.
|
|
type NodeNavigator struct {
|
|
root, cur *Node
|
|
}
|
|
|
|
func (a *NodeNavigator) Current() *Node {
|
|
return a.cur
|
|
}
|
|
|
|
func (a *NodeNavigator) NodeType() xpath.NodeType {
|
|
switch a.cur.Type {
|
|
case TextNode:
|
|
return xpath.TextNode
|
|
case DocumentNode:
|
|
return xpath.RootNode
|
|
case ElementNode:
|
|
return xpath.ElementNode
|
|
default:
|
|
panic(fmt.Sprintf("unknown node type %v", a.cur.Type))
|
|
}
|
|
}
|
|
|
|
func (a *NodeNavigator) LocalName() string {
|
|
return a.cur.Data
|
|
|
|
}
|
|
|
|
func (a *NodeNavigator) Prefix() string {
|
|
return ""
|
|
}
|
|
|
|
func (a *NodeNavigator) Value() string {
|
|
switch a.cur.Type {
|
|
case ElementNode:
|
|
return a.cur.InnerText()
|
|
case TextNode:
|
|
return a.cur.Data
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (a *NodeNavigator) Copy() xpath.NodeNavigator {
|
|
n := *a
|
|
return &n
|
|
}
|
|
|
|
func (a *NodeNavigator) MoveToRoot() {
|
|
a.cur = a.root
|
|
}
|
|
|
|
func (a *NodeNavigator) MoveToParent() bool {
|
|
if n := a.cur.Parent; n != nil {
|
|
a.cur = n
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (x *NodeNavigator) MoveToNextAttribute() bool {
|
|
return false
|
|
}
|
|
|
|
func (a *NodeNavigator) MoveToChild() bool {
|
|
if n := a.cur.FirstChild; n != nil {
|
|
a.cur = n
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (a *NodeNavigator) MoveToFirst() bool {
|
|
for n := a.cur.PrevSibling; n != nil; n = n.PrevSibling {
|
|
a.cur = n
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (a *NodeNavigator) String() string {
|
|
return a.Value()
|
|
}
|
|
|
|
func (a *NodeNavigator) MoveToNext() bool {
|
|
if n := a.cur.NextSibling; n != nil {
|
|
a.cur = n
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (a *NodeNavigator) MoveToPrevious() bool {
|
|
if n := a.cur.PrevSibling; n != nil {
|
|
a.cur = n
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (a *NodeNavigator) MoveTo(other xpath.NodeNavigator) bool {
|
|
node, ok := other.(*NodeNavigator)
|
|
if !ok || node.root != a.root {
|
|
return false
|
|
}
|
|
a.cur = node.cur
|
|
return true
|
|
}
|