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  }