HTML element to absolute XPath selector - JavaScript
Tags: queryselector, javascript, xpath, tutorial
Published: 2022-11-19 19:16:38

[XPath](https://www.w3schools.com/xml/xpath_intro.asp) selector is convenient in some situations, including a page that **randomly generates a new id and class** and many more. Let's see how we can get the full XPath position by using an element.

**we will use the child to parent architecture. **

Create a function that receive an element. We will do all work in this function
```javascript
function getXPath(element) {
   // Selector
    let selector = '';

  // ... Add code here
}
```

Get tag name of current element
```javascript
// Get element tag name 
        const tagName = currentElement.tagName.toLowerCase();
```

Get parent element
```javascript
  // Get parent element
        const parentElement = currentElement.parentElement;
```

Is current element is the only child of `parentElement` if true then add tag to `selector`;
```javascript
 // Count children
        if (parentElement.childElementCount > 1) {
        
        } else {
            //* Current element has no siblings
            // Append tag to selector
            selector = `/${tagName}${selector}`;
        }
```

If not the only child get other child and filter elements from these elements, that has the same tagname of current tag
```javascript
 // Count children
        if (parentElement.childElementCount > 1) {


           // Get children of parent element
            const parentsChildren = [...parentElement.children];
            // Count current tag 
            let tag = [];
            parentsChildren.forEach(child => {
                if (child.tagName.toLowerCase() === tagName) tag.push(child) // Append to tag
            })


        } else {
            //* Current element has no siblings
            // Append tag to selector
            selector = `/${tagName}${selector}`;
        }
```

Now check, is the current element only of type in parent. If so, add to selector `/tagName`

```javascript
 // Count children
        if (parentElement.childElementCount > 1) {

           // ...
          // Is only of type
            if (tag.length === 1) {
                // Append tag to selector
                selector = `/${tagName}${selector}`;
            }


        } else {
            //* Current element has no siblings
            // Append tag to selector
            selector = `/${tagName}${selector}`;
        }
```

If not then add tag position like `/tagName[number]`

```javascript
 // Count children
        if (parentElement.childElementCount > 1) {

           // ...
          // Is only of type
            if (tag.length === 1) {
                // Append tag to selector
                selector = `/${tagName}${selector}`;
            } else {
                // Get position of current element in tag
                const position = tag.indexOf(currentElement) + 1;
                // Append tag to selector
                selector = `/${tagName}[${position}]${selector}`;
            }


        } else {
            //* Current element has no siblings
            // Append tag to selector
            selector = `/${tagName}${selector}`;
        }
```

Now we need to repeate this method until we found html tag. Add a while loop. And some variable to help
```javascript
 function getXPath(element) {
    //...

    // Loop handler
    let foundRoot;
    // Element handler
    let currentElement = element;

       // Do action until we reach html element
    do {
        // Get element tag name 
        const tagName = currentElement.tagName.toLowerCase();
// ...

        // Set parent element to current element
        currentElement = parentElement;
        // Is root  
        foundRoot = parentElement.tagName.toLowerCase() === 'html';
        // Finish selector if found root element
        if(foundRoot) selector = `/html${selector}`;
    }
    while (foundRoot === false);

```

And finally return selector
```javascript
    // Return selector
    return selector;
```

Here is the full code. [element-to-path.js](https://gist.github.com/abkarim/ab0e0e3b629e9a80c31db323f4373bcb)
```javascript
/**
 * Get absolute xPath position from dom element
 * xPath position will does not contain any id, class or attribute, etc selector
 * Because, Some page use random id and class. This function should ignore that kind problem, so we're not using any selector
 * 
 * @param {Element} element element to get position
 * @returns {String} xPath string
 */
 function getXPath(element) {
    // Selector
    let selector = '';
    // Loop handler
    let foundRoot;
    // Element handler
    let currentElement = element;

    // Do action until we reach html element
    do {
        // Get element tag name 
        const tagName = currentElement.tagName.toLowerCase();
        // Get parent element
        const parentElement = currentElement.parentElement;

        // Count children
        if (parentElement.childElementCount > 1) {
            // Get children of parent element
            const parentsChildren = [...parentElement.children];
            // Count current tag 
            let tag = [];
            parentsChildren.forEach(child => {
                if (child.tagName.toLowerCase() === tagName) tag.push(child) // Append to tag
            })

            // Is only of type
            if (tag.length === 1) {
                // Append tag to selector
                selector = `/${tagName}${selector}`;
            } else {
                // Get position of current element in tag
                const position = tag.indexOf(currentElement) + 1;
                // Append tag to selector
                selector = `/${tagName}[${position}]${selector}`;
            }

        } else {
            //* Current element has no siblings
            // Append tag to selector
            selector = `/${tagName}${selector}`;
        }

        // Set parent element to current element
        currentElement = parentElement;
        // Is root  
        foundRoot = parentElement.tagName.toLowerCase() === 'html';
        // Finish selector if found root element
        if(foundRoot) selector = `/html${selector}`;
    }
    while (foundRoot === false);

    // Return selector
    return selector;
}
```

### Example
```javascript
const button = document.querySelector("#main > div:nth-child(27) > a.w3-left.w3-btn");

getXPath(button)
```
returns
```javascript
'/html/body/div[7]/div[1]/div[1]/div[4]/a[1]'
```
 
To learn more about Xpath https://www.w3schools.com/xml/xpath_intro.asp

[My github profile](https://github.com/abkarim)

Please give a feedback, what are you thinking about this? and do you had a better solution?