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  }