Get Xpath of Node
WAY29 opened this issue · comments
Longlone commented
Is there a method or function that can get xpath from *xmlquery.Node? Sometimes this is useful.
In order to implement a function, I had to write the following code, I think this code is very inefficient and maybe wrong. The Xpath of each node should be obtained during Parse:
func GetXpathFromNode(node *xmlquery.Node) string {
var getXpathFromNode func(node *xmlquery.Node, depth int, path string) string
getXpathFromNode = func(node *xmlquery.Node, depth int, path string) string {
if node == nil {
return ""
}
nodeType := node.Type
if nodeType == xmlquery.CommentNode || nodeType == xmlquery.DeclarationNode || nodeType == xmlquery.CharDataNode {
return ""
}
data := node.Data
prefix := ""
switch nodeType {
case xmlquery.TextNode:
path = "text()"
case xmlquery.DocumentNode:
prefix = "/"
case xmlquery.ElementNode:
prefix = data
case xmlquery.AttributeNode:
prefix = "@" + data
}
hasIndex := false
if node.PrevSibling != nil {
count := 0
for prev := node.PrevSibling; prev != nil; prev = prev.PrevSibling {
if prev.Type == node.Type && prev.Data == data {
count++
}
}
if count > 0 {
prefix = fmt.Sprintf("%s[%d]", prefix, count+1)
hasIndex = true
}
}
if !hasIndex && node.NextSibling != nil {
existed := false
for next := node.NextSibling; next != nil; next = next.NextSibling {
if next.Type == node.Type && next.Data == data {
existed = true
break
}
}
if existed {
prefix = fmt.Sprintf("%s[1]", prefix)
}
}
if prefix != "" {
if !strings.HasSuffix(prefix, "/") {
prefix += "/"
}
path = prefix + path
}
if depth < 128 && node.Parent != nil {
path = getXpathFromNode(node.Parent, depth+1, path)
}
return strings.TrimRight(path, "/")
}
return getXpathFromNode(node, 0, "")
}