Skip to content

Get Xpath of Node #112

Description

@WAY29

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, "")
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions