Skip to content

Get Xpath of Node #112

@WAY29

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

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