Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get Xpath of Node #112

Open
WAY29 opened this issue Feb 27, 2024 · 0 comments
Open

Get Xpath of Node #112

WAY29 opened this issue Feb 27, 2024 · 0 comments

Comments

@WAY29
Copy link

WAY29 commented Feb 27, 2024

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, "")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant