github.com/avicd/go-utilx@v0.1.0/xmlx/xnode.go (about) 1 package xmlx 2 3 import ( 4 "strings" 5 ) 6 7 type XNodeHandler func(node *Node) bool 8 9 type XNode struct { 10 *Node 11 handleNode XNodeHandler 12 } 13 14 func NewXpathNode(node *Node) *XNode { 15 return &XNode{Node: node} 16 } 17 18 func chooseNode(node *Node, sel string) bool { 19 if strings.HasSuffix(sel, "()") { 20 switch sel { 21 case "node()": 22 return true 23 case "text()": 24 return node.Type == TextNode 25 } 26 } 27 28 if node.Type != ElementNode && node.Type != DocumentNode { 29 return false 30 } 31 if sel == "*" { 32 return true 33 } 34 return sel == node.Name 35 } 36 37 func (it *XNode) setCheckin(checker XNodeHandler) { 38 it.handleNode = checker 39 } 40 41 func (it *XNode) Ancestor(sel string) { 42 for p := it.ParentNode; p != nil; p = p.ParentNode { 43 if !chooseNode(p, sel) { 44 continue 45 } 46 if !it.handleNode(p) { 47 break 48 } 49 } 50 } 51 52 func (it *XNode) AncestorOrSelf(sel string) { 53 if !it.chooseSelf(sel) { 54 return 55 } 56 it.Ancestor(sel) 57 } 58 59 func (it *XNode) Attribute(sel string) { 60 for _, p := range it.Attrs { 61 if sel == p.Name && !it.handleNode(p) { 62 break 63 } 64 } 65 } 66 67 func (it *XNode) Child(sel string) { 68 for _, p := range it.ChildNodes { 69 if chooseNode(p, sel) && !it.handleNode(p) { 70 break 71 } 72 } 73 } 74 75 func nodeTreeLoop(node *Node, sel string, handleNode XNodeHandler) { 76 for _, p := range node.ChildNodes { 77 if chooseNode(p, sel) && !handleNode(p) { 78 break 79 } 80 if len(p.ChildNodes) > 0 { 81 nodeTreeLoop(p, sel, handleNode) 82 } 83 } 84 } 85 86 func (it *XNode) Descendant(sel string) { 87 nodeTreeLoop(it.Node, sel, it.handleNode) 88 } 89 90 func (it *XNode) DescendantOrSelf(sel string) { 91 if !it.chooseSelf(sel) { 92 return 93 } 94 it.Descendant(sel) 95 } 96 97 func (it *XNode) Following(sel string) { 98 for p := it.NextSibling; p != nil; p = p.NextSibling { 99 xnd := NewXpathNode(p) 100 next := true 101 xnd.setCheckin(func(node *Node) bool { 102 next = it.handleNode(node) 103 return next 104 }) 105 xnd.DescendantOrSelf(sel) 106 if !next { 107 return 108 } 109 } 110 if it.ParentNode != nil { 111 xnd := NewXpathNode(it.ParentNode) 112 xnd.setCheckin(func(node *Node) bool { 113 return it.handleNode(node) 114 }) 115 xnd.Following(sel) 116 } 117 } 118 119 func (it *XNode) Namespace(sel string) { 120 if it.NamespaceURI == sel { 121 it.handleNode(it.Node) 122 } 123 } 124 125 func (it *XNode) Parent() { 126 if chooseNode(it.Node, "*") { 127 it.handleNode(it.ParentNode) 128 } 129 } 130 131 func (it *XNode) Preceding(sel string) { 132 if !it.chooseSelf(sel) { 133 return 134 } 135 it.PrecedingSibling(sel) 136 } 137 138 func (it *XNode) PrecedingSibling(sel string) { 139 for p := it.PrevSibling; p != nil; p = p.PrevSibling { 140 if !it.handleNode(p) { 141 break 142 } 143 } 144 } 145 146 func (it *XNode) Self(sel string) { 147 it.chooseSelf(sel) 148 } 149 150 func (it *XNode) Root() { 151 root := it.GetRoot() 152 if chooseNode(root, "*") { 153 it.handleNode(root) 154 } 155 } 156 157 func (it *XNode) chooseSelf(sel string) bool { 158 if chooseNode(it.Node, sel) && !it.handleNode(it.Node) { 159 return false 160 } 161 return true 162 }