github.com/avicd/go-utilx@v0.1.0/xmlx/node.go (about) 1 package xmlx 2 3 import ( 4 "github.com/avicd/go-utilx/logx" 5 "strings" 6 ) 7 8 type NodeType uint 9 10 const ( 11 ElementNode NodeType = iota 12 AttributeNode 13 TextNode 14 CDataSectionNode 15 ProcessingInstructionNode 16 CommentNode 17 DocumentNode 18 DocumentTypeNode 19 DirectiveNode 20 ) 21 22 type Node struct { 23 ParentNode, 24 FirstChild, 25 LastChild, 26 PrevSibling, 27 NextSibling *Node 28 Type NodeType 29 Value string 30 Name string 31 NamespaceURI string 32 Prefix string 33 Attrs []*Node 34 ChildNodes []*Node 35 } 36 37 func (node *Node) AppendChild(child *Node) { 38 if child == nil { 39 return 40 } 41 child.ParentNode = node 42 child.PrevSibling = node.LastChild 43 node.ChildNodes = append(node.ChildNodes, child) 44 if node.LastChild != nil { 45 node.LastChild.NextSibling = child 46 } 47 if node.FirstChild == nil { 48 node.FirstChild = child 49 } 50 node.LastChild = child 51 } 52 53 func (node *Node) AppendAll(nodes []*Node) { 54 for _, p := range nodes { 55 node.AppendChild(p) 56 } 57 } 58 59 func cloneNodeList(list []*Node, parent *Node) []*Node { 60 var newList []*Node 61 for i, node := range list { 62 node = node.CloneNode(true) 63 node.ParentNode = parent 64 if i > 0 { 65 node.PrevSibling = newList[i-1] 66 node.PrevSibling.NextSibling = node 67 } 68 newList = append(newList, node) 69 } 70 return newList 71 } 72 73 func (node *Node) CloneNode(deep bool) *Node { 74 if node == nil { 75 return nil 76 } 77 newNode := &Node{ 78 FirstChild: node.FirstChild, 79 LastChild: node.LastChild, 80 PrevSibling: node.PrevSibling, 81 NextSibling: node.NextSibling, 82 Type: node.Type, 83 Value: node.Value, 84 Name: node.Name, 85 NamespaceURI: node.NamespaceURI, 86 Prefix: node.Prefix, 87 Attrs: node.Attrs, 88 ChildNodes: node.ChildNodes, 89 } 90 newNode.Attrs = cloneNodeList(node.Attrs, newNode) 91 if deep { 92 if len(node.Attrs) > 0 { 93 newNode.Attrs = cloneNodeList(node.Attrs, newNode) 94 } 95 if len(node.ChildNodes) > 0 { 96 nodeList := cloneNodeList(node.ChildNodes, newNode) 97 newNode.ChildNodes = nodeList 98 newNode.FirstChild = nodeList[0] 99 newNode.LastChild = nodeList[len(nodeList)-1] 100 } 101 } 102 return newNode 103 } 104 105 func (node *Node) InsertBefore(newNode *Node, refNode *Node) { 106 index := node.IndexOf(refNode) 107 if index < 0 { 108 logx.Error("Invalid ref node when calling *Node.InsertBefore") 109 return 110 } 111 newNode.ParentNode = node 112 var nodeList []*Node 113 if index > 0 { 114 nodeList = node.ChildNodes[:index-1] 115 } else { 116 node.FirstChild = newNode 117 } 118 nodeList = append(nodeList, newNode) 119 nodeList = append(nodeList, node.ChildNodes[index-1:]...) 120 node.ChildNodes = nodeList 121 if refNode.PrevSibling != nil { 122 refNode.PrevSibling.NextSibling = newNode 123 } 124 newNode.PrevSibling = refNode.PrevSibling 125 newNode.NextSibling = refNode 126 refNode.PrevSibling = newNode 127 } 128 129 func (node *Node) InsertAfter(newNode *Node, refNode *Node) { 130 index := node.IndexOf(refNode) 131 if index < 0 { 132 logx.Error("Invalid ref node when calling *Node.InsertAfter") 133 return 134 } 135 newNode.ParentNode = node 136 var nodeList []*Node 137 if refNode.NextSibling != nil { 138 nodeList = append(node.ChildNodes[:index+1], newNode) 139 nodeList = append(nodeList, node.ChildNodes[index+1:]...) 140 } else { 141 nodeList = append(node.ChildNodes, newNode) 142 } 143 node.ChildNodes = nodeList 144 if refNode.NextSibling != nil { 145 refNode.NextSibling.PrevSibling = newNode 146 } 147 newNode.NextSibling = node.NextSibling 148 newNode.PrevSibling = refNode 149 refNode.NextSibling = newNode 150 } 151 152 func (node *Node) AddSibling(next *Node) { 153 if next == nil { 154 return 155 } 156 node.ParentNode.InsertAfter(next, node) 157 } 158 159 func (node *Node) Remove() { 160 if node.ParentNode != nil { 161 node.ParentNode.RemoveChild(node) 162 } 163 } 164 165 func (node *Node) RemoveChild(child *Node) { 166 ni := node.IndexOf(child) 167 if ni > -1 { 168 if child.PrevSibling != nil { 169 child.PrevSibling.NextSibling = child.NextSibling 170 } 171 if child.NextSibling != nil { 172 child.NextSibling.PrevSibling = child.PrevSibling 173 } 174 if child == node.FirstChild { 175 node.FirstChild = child.NextSibling 176 } 177 if child == node.LastChild { 178 node.LastChild = child.PrevSibling 179 } 180 buf := node.ChildNodes[:ni] 181 node.ChildNodes = append(buf, node.ChildNodes[ni+1:]...) 182 } 183 } 184 185 func (node *Node) RemoveAll(list []*Node) { 186 for _, nd := range list { 187 node.RemoveChild(nd) 188 } 189 } 190 191 func (node *Node) ClearContent() { 192 node.ChildNodes = nil 193 node.FirstChild = nil 194 node.LastChild = nil 195 } 196 197 func (node *Node) IndexOf(ref *Node) int { 198 for i, p := range node.ChildNodes { 199 if p == ref { 200 return i 201 } 202 } 203 return -1 204 } 205 206 func (node *Node) Contains(ref *Node) bool { 207 for _, p := range node.ChildNodes { 208 if p == ref || p.Contains(ref) { 209 return true 210 } 211 } 212 return false 213 } 214 215 func (node *Node) HasChildren() bool { 216 return len(node.ChildNodes) > 0 217 } 218 219 func (node *Node) GetRoot() *Node { 220 var p *Node 221 for p = node; p.ParentNode != nil; p = p.ParentNode { 222 } 223 return p 224 } 225 226 func (node *Node) Attr(name string) *Node { 227 if node.Type == AttributeNode { 228 if node.Name == name { 229 return node 230 } 231 } else { 232 for _, attr := range node.Attrs { 233 if attr.Name == name { 234 return attr 235 } 236 } 237 } 238 return nil 239 } 240 241 func (node *Node) AttrString(name string) string { 242 if attr := node.Attr(name); attr != nil { 243 return attr.Value 244 } 245 return "" 246 } 247 248 func (node *Node) TrimAttrString(name string) string { 249 return strings.TrimSpace(node.AttrString(name)) 250 } 251 252 func (node *Node) AttrBool(name string) bool { 253 return strings.TrimSpace(node.TrimAttrString(name)) == "true" 254 } 255 256 func (node *Node) InnerText() string { 257 switch node.Type { 258 case ElementNode, DocumentNode: 259 buffer := strings.Builder{} 260 for _, p := range node.ChildNodes { 261 buffer.WriteString(p.InnerText()) 262 } 263 return buffer.String() 264 case TextNode, CDataSectionNode, CommentNode: 265 return node.Value 266 } 267 return "" 268 } 269 270 func (node *Node) NameWithPrefix() string { 271 name := node.Name 272 if node.Prefix != "" { 273 name = node.Prefix + ":" + name 274 } 275 return name 276 } 277 278 func (node *Node) InnerXML() string { 279 exporter := &Exporter{IncludeSelf: false} 280 return exporter.ApplyOn(node) 281 } 282 283 func (node *Node) InnerHTML() string { 284 return node.InnerXML() 285 } 286 287 func (node *Node) Export(exporter *Exporter) string { 288 return exporter.ApplyOn(node) 289 } 290 291 func (node *Node) Find(selector string) []*Node { 292 xpath, err := NewXpath(selector) 293 if err != nil { 294 logx.Error(err.Error()) 295 return nil 296 } 297 return xpath.SelectAll(node) 298 } 299 300 func (node *Node) FindOne(selector string) *Node { 301 xpath, err := NewXpath(selector) 302 if err != nil { 303 logx.Error(err.Error()) 304 return nil 305 } 306 return xpath.SelectFirst(node) 307 }