<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nilton</title>
    <description>The latest articles on DEV Community by Nilton (@nltncsr).</description>
    <link>https://dev.to/nltncsr</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F577235%2F3c9e13ee-6cf9-485d-a764-87b3cae5d97c.jpeg</url>
      <title>DEV Community: Nilton</title>
      <link>https://dev.to/nltncsr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nltncsr"/>
    <language>en</language>
    <item>
      <title>Extraindo o XPath de um elemento no navegador</title>
      <dc:creator>Nilton</dc:creator>
      <pubDate>Mon, 15 Feb 2021 16:40:44 +0000</pubDate>
      <link>https://dev.to/nltncsr/extraindo-o-xpath-de-um-elemento-no-navegador-29ng</link>
      <guid>https://dev.to/nltncsr/extraindo-o-xpath-de-um-elemento-no-navegador-29ng</guid>
      <description>&lt;p&gt;&lt;em&gt;(Ilustração da capa por Ilya Nazarov em &lt;a href="https://www.artstation.com/artwork/ez82Y"&gt;ArtStation&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Porque eu deveria me importar
&lt;/h1&gt;

&lt;p&gt;Todo mundo que manipula elementos HTML está familiarizado com métodos como &lt;code&gt;querySelector()&lt;/code&gt;, &lt;code&gt;querySelectorAll()&lt;/code&gt;, ou outros antigos e ainda suportados como &lt;code&gt;getElementById()&lt;/code&gt; e variações. A ideia deles é encontrar elementos a partir de seletores como classes CSS, ids, nomes das tags, entre outros. Algumas vezes, é preciso encontrar um &lt;em&gt;seletor universal&lt;/em&gt;, algo que identifique especificamente qual é o elemento. O XPath pode ser uma alternativa pra isso.&lt;/p&gt;

&lt;h1&gt;
  
  
  O que é XPath
&lt;/h1&gt;

&lt;p&gt;Se pensarmos na DOM como uma estrutura em árvore com suas muitas divisões e &lt;em&gt;galhos&lt;/em&gt;, seria possível localizar qualquer ponto nela indicando o caminho a ser percorrido. Pra exemplificar a metáfora da árvore: se pensarmos nas centenas ou milhares de folhas que uma árvore pode ter, seria muito complicado apontar pra alguém uma determinada folha dizendo "é  aquela verde" ou "a que tá virada pra cima". É muito mais &lt;strong&gt;preciso&lt;/strong&gt; dizer "depois do segundo galho que vem do tronco, tem outros dois menores, e uns ramos... é a folha que tá no primeiro". De forma muita rasa e concisa, o XPath é esse caminho, só que pra &lt;a href="https://developer.mozilla.org/pt-BR/docs/DOM/Referencia_do_DOM/Introdu%C3%A7%C3%A3o"&gt;árvore do DOM&lt;/a&gt;. Considere o trecho HTML a seguir:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se quiséssemos pegar, digamos, algum &lt;code&gt;span&lt;/code&gt; dentro de um &lt;code&gt;div&lt;/code&gt;, não teríamos exatamente uma maneira precisa de dizer qual elemento queremos, pois os métodos citados lá atrás retornariam listas de elementos. Esses elementos também não tem seletores específicos como classes ou atributos HTML. Se quisesse o segundo &lt;code&gt;span&lt;/code&gt; do terceiro &lt;code&gt;div&lt;/code&gt;, por exemplo, teríamos que dizer "segundo &lt;code&gt;span&lt;/code&gt;, dentro do terceiro &lt;code&gt;div&lt;/code&gt;, dentro do &lt;code&gt;body&lt;/code&gt;".&lt;br&gt;
É aí que o XPath entra em ação, ele é &lt;strong&gt;literalmente&lt;/strong&gt; isso:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;/html/body/div[3]/span[2]&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;É uma &lt;em&gt;notação&lt;/em&gt; muito familiar, muito parecido com árvores de diretórios, seria algo como "dentro de &lt;code&gt;html&lt;/code&gt;, dentro de &lt;code&gt;body&lt;/code&gt;, dentro do terceiro &lt;code&gt;div&lt;/code&gt;, selecione o segundo &lt;code&gt;span&lt;/code&gt;. O mais interessante é que seria uma espécie de seletor universal. É uma notação interessante que pode ser comunicada entre plataformas, guardada na aplicação pra algum uso futuro, replicada em algum outro momento. Existem inúmeros problemas específicos que o XPath soluciona justamente pela flexibilidade de uso.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;É precisar observar que, diferentemente da indexação de arrays em JS, num XPath ela começa no &lt;code&gt;1&lt;/code&gt; e não no &lt;code&gt;0&lt;/code&gt;, ou seja, o segundo elemento vai ser achado pelo índice &lt;code&gt;[2]&lt;/code&gt; e não &lt;code&gt;[1]&lt;/code&gt;. Ao lidar com os arrays dos elementos no código, é preciso &lt;em&gt;compensar&lt;/em&gt; essa diferença.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Se você quiser entender a fundo mesmo, recomendo olhar a &lt;a href="https://www.w3.org/TR/1999/REC-xpath-19991116"&gt;documentação oficial&lt;/a&gt;. Ela talvez seja demais pra esse artigo, mas vale a pena ao fim dele entrar e tentar descobrir novas formas de implementar o que tá descrito lá.&lt;br&gt;
Por padrão, os navegadores não implementam um método de encontrarmos o XPath de um elemento, por isso temos que pensar numa maneira de, quando precisarmos, implementar a lógica por trás pra geração desse caminho.&lt;/p&gt;
&lt;h1&gt;
  
  
  Implementação básica
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Pensando no código
&lt;/h2&gt;

&lt;p&gt;Bom, o raciocínio inicial é: percorrer a árvore do DOM até o elemento raiz (&lt;code&gt;html&lt;/code&gt;) e ir montando o nosso XPath de acordo. Pra isso, eu resolvi colocar toda a lógica dentro de uma só função, que recebe o elemento e retorna o XPath como string. Sem muito mistério, direto ao ponto.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getXPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na função, achei que seria interessante separar o processo em duas etapas: 1) coletar todos os elementos da árvore de ascendência, a partir do elemento inicial até o &lt;code&gt;html&lt;/code&gt;, e depois 2) montar a partir disso o XPath. Seguindo o raciocínio da primeira parte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// Array que vai guardar os elementos ascendentes em ordem&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ascendingElements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="c1"&gt;// Guarda o primeiro elemento logo de cara, já que ele obviamente faz parte do XPath&lt;/span&gt;
  &lt;span class="nx"&gt;ascendingElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Estrutura do/while, que executa a iteração enquanto houver elementos pai&lt;/span&gt;
  &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;ascendingElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ascendingElements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;parentElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ascendingElements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;parentElement&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dentro do &lt;code&gt;do..while&lt;/code&gt; o que acontece é: verificamos se o primeiro elemento do array tem um pai válido (não-nulo). Se tem, adiciona ele a mesma lista no &lt;strong&gt;começo&lt;/strong&gt; usando o método &lt;code&gt;unshift()&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Nota: Dá pra usar aqui o método &lt;code&gt;push()&lt;/code&gt; também, só lembrando que ele insere o item no &lt;strong&gt;fim&lt;/strong&gt; do array, então sempre teríamos que verificar qual é o &lt;em&gt;último&lt;/em&gt; elemento utilizando &lt;code&gt;length - 1&lt;/code&gt; do próprio array, e depois teríamos que inverter a ordem do array completo pra montar o XPath corretamente. Não tem problema nenhum, só considerei que seria um pouco mais legível assim.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ao atingirmos um &lt;code&gt;parentElement&lt;/code&gt; igual a &lt;code&gt;null&lt;/code&gt;, significa que atingimos o fim do documento, ou seja, o próprio &lt;code&gt;html&lt;/code&gt;, já que ele não tem elemento pai. O loop então se encerra e teremos no array &lt;code&gt;ascendingElements&lt;/code&gt; todos os elementos em ordem.&lt;br&gt;
A partir de então podemos trabalhar na criação do XPath em si. Todos os elementos podem ter seu nome acessado através da propriedade &lt;code&gt;tagName&lt;/code&gt; e facilmente poderemos percorrer o array concatenando os nomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// Criamos um novo array através de .map() iterando sobre os elementos e retornando só os seus nomes&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orderedTagNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ascendingElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tagName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// Podemos juntar todas as strings, colocando entre elas uma "/" e transformando tudo em minúscula, já que `tagName` retorna o nome em maiúsculo.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;xPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;orderedTagNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;// A função retorna a string completa concatenada a uma barra inicial, indicando que ali é a raiz do documento.&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;xPath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A função completa seria então&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getXPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ascendingElements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="nx"&gt;ascendingElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ascendingElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ascendingElements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;parentElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ascendingElements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;parentElement&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orderedTagNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ascendingElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tagName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;xPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;orderedTagNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;xPath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Temos a função completa! Ela retorna o XPath de um elemento completo. Vamos aplicar ao exemplo do início do texto. Se formos tentar criar o XPath do segundo &lt;code&gt;span&lt;/code&gt; do terceiro elemento &lt;code&gt;div&lt;/code&gt;, por exemplo, teremos&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;/html/body/div/span&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;À primeira vista tudo certo, porém não temos a indicação da ordem do elemento! Se fossemos seguir esse XPath gerado, pegaríamos o primeiro &lt;code&gt;span&lt;/code&gt; dentro do primeiro &lt;code&gt;div&lt;/code&gt;. O nosso código não leva em conta que podem haver elementos de mesmo nome filhos do mesmo pai. O certo nesse exemplo seria indicar que era o &lt;code&gt;span[2]&lt;/code&gt; depois de &lt;code&gt;div[3]&lt;/code&gt;, de acordo com a especificação. Pra resolver isso, poderíamos então verificar em qual posição o elemento filho está &lt;em&gt;relativa ao seus similares&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// Vamos retornar o nome dos elementos já com a indicação da sua posição&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orderedTagNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ascendingElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;elementLevel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;elementSelector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tagName&lt;/span&gt;

    &lt;span class="c1"&gt;// Um contador pra guardar, dentro de cada novo elemento que estamos verificando, em qual ordem ele está entre os seus similires&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sameTagNameCounter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ascendingElements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;elementLevel&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;ascendingElements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;elementLevel&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// Se o elemento tem nome igual, adicionamos uma unidade ao seu contador. Ele servirá pra montarmos o nome com a posição correta ao fim do loop&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elementSelector&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tagName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;sameTagNameCounter&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Não precisamos conhecer quais são todos os elementos filhos em comum, precisamos encontrar somente a posição do elemento atual e depois disso podemos encerrar o loop&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Aplica a formatação "nomeDaTag[posição]" caso tenhamos mais de um elemento&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;elementSelector&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;sameTagNameCounter&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`[&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sameTagNameCounter&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;]`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora sim, se executarmos a função com o mesmo exemplo, teremos o resultado correto.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;/html/body/div[3]/span[2]&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Melhoramentos
&lt;/h1&gt;

&lt;p&gt;Existem muitas maneiras de implementar essa lógica. Essa é mais uma sugestão simplificada do que regra, mas que poderia ter sido feita de outras formas. Poderíamos usar recursividade e diminuir algumas linhas de código? Com certeza. A manipulação dos elementos poderia ter sido feita com outros métodos? Há uma infinidade de maneiras de se abordar o mesmo problema, e contanto que resolva e siga boas práticas, tá tudo bem. Poderíamos desestruturar essa função em duas ou mais? Se estivéssemos em produção eu diria que &lt;em&gt;deveríamos&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Mas não só do ponto de vista técnico, mas também do funcional. O XPath é uma notação extremamente robusta: é possível também usar funções pra selecionar algum id específico, acessar via seletores CSS, atributos e mais uma infinidade de coisas. Tem uma colinha bem legal &lt;a href="https://devhints.io/xpath"&gt;aqui&lt;/a&gt;, recomendo.&lt;br&gt;
O código que a gente trabalhou é funcional, mas também é bem básico. Pra solucionar problemas mais complexos ou cenários mais robustos, considere pesquisar alguma biblioteca já bem estabelecida que resolva esses problemas.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>braziliandevs</category>
    </item>
  </channel>
</rss>
