2

What I am trying to accomplish is basically, to get a list of Elements ( currently using document.querySelectorAll() in order to get a list of elements using a general selector. E.g: get me all elements of .note class in the document.

document.querySelectorAll('.note')

since it collects them from all over the DOM, I then need a JS function to iterate over all of them using a different function from a library that does not use NodeList, and I need it to query all these elements individually (This is an automation task so negligent benefits of speed are of no matter here).

Since these elements appear on different parts and hierarchies of the DOM, I cannot fetch them all with a CSS selector individually like :nth-of-type, I need the specific CSS Selector/ XPath of each of them. For example, for all .note class elements on a page, I need the result to be something like:

['.my-first-class .inner .note', 'section .different-class .inner .note', '.profile .profile-notes .note']

something in this style would be extremely helpful to me.

Thank you very much for any assistance you may provide!

TomDGW2
  • 29
  • 6
  • My opinion: use `id` - that's what I do - and I get dissed over here for it: "query selector blah blah blah!!!" – iAmOren Jul 31 '20 at 04:56
  • Do you need to use a function that does not use NodeList because you're supporting old IE? – cam Jul 31 '20 at 04:57
  • So you need the list with third level parent? – Jobelle Jul 31 '20 at 05:01
  • @iAmOren were it possible to retroactively add an ID to hundreds of elements on a website I do not have direct authority to edit for my purposes, certainly that would have been beneficial. Unfortunately I have to work with what I got, and specific CSS/ Xpath is the way. – TomDGW2 Jul 31 '20 at 08:25
  • @camaulay I am not using it through a browser but using an automation test built in Nightwatch.js, and Nightwatch does not interact directly with the browser but through Selenium drivers, which don't give me back NodeList objects. – TomDGW2 Jul 31 '20 at 08:25

2 Answers2

1

I borrowed a generateQuerySelector function from this answer and simply looped over the results of .note query selection, being sure to convert the NodeList to an Array.

const notes = Array.from(document.querySelectorAll('.note'))
notes.forEach(note => {
  console.log(generateQuerySelector(note))
})

function generateQuerySelector (el) {
  if (el.tagName.toLowerCase() == "html")
      return "HTML";
  var str = el.tagName;
  str += (el.id != "") ? "#" + el.id : "";
  if (el.className) {
      var classes = el.className.split(/\s/);
      for (var i = 0; i < classes.length; i++) {
          str += "." + classes[i]
      }
  }
  return generateQuerySelector(el.parentNode) + " > " + str;
}
<div class="content">
  <div class="primary">
    <div class="article">
      <div class="note">
      </div>
    </div>
  </div>
  <div class="secondary">
    <div class="aside">
      <div class="note">
      </div>
    </div>
  </div>
  <div class="note">
  </div>
  <div id="contact-form">
    <div class="note"></div>
  </div>
</div>
cam
  • 3,179
  • 1
  • 12
  • 15
  • 1
    Wow, can't believe I didn't think to just do recursion on the parents! I guess I was also worrying about performance but like I said, speed isn't a big issue, so this helps alot!. I did notice this won't uniquely identify the elements, but I decided to solve this by comparing previously queried element against the current one in the list and should they be the same, add an `nth-child()` to the selector depending on a counter. Thank you! – TomDGW2 Jul 31 '20 at 08:21
  • Ah yes `nth-child()` will allow you to select specific siblings, good luck! – cam Jul 31 '20 at 08:29
0

Css can't write it down, it can only show you whatever you want in the way you want

body *{ display: block} /* only if you want single column */  
.wanted::after{ content: ' wanted '; float: right; background: red; color: #000; margin: 0 5px; padding: 0 5px}  
p.wanted::after{ content: 'I am a <p>'; background: #cf8;}  
div.wanted::after{ content: 'I am a <div>'; background: yellow}  
a.wanted::after{ content: 'href me';background: orange}  

<div>div</div>  
<a href="">link</a>  
<p>paragraph</p>  
<a class="wanted">link</a>  
<a href="">link</a>  
<div>div</div>  
<div class="wanted">div</div>  
<a href="">link</a>  
<a class="wanted">link</a>  
<nav class="wanted">nav</nav>  
<div class="wanted"> div </div>  
<div>div</div>  
<p>paragraph</p>  
<div class="wanted"> div </div>  
<p class="wanted">paragraph</p>  
<a href="">link</a>  
<div class="wanted"> div </div>  
<a class="wanted">link</a>  
<a class="wanted">link</a>  
<div class="wanted"> div </div>  
<p class="wanted">paragraph</p>  
<div>div</div>  
<div class="wanted"> div </div>  
<a href="">link</a>  
<div class="wanted"> div </div>  
<p class="wanted">paragraph</p>  
<div>div</div>  
<a class="wanted">link</a>  
<div class="wanted"> div </div>  
<div>div</div>  
<p>paragraph</p>  
<div class="wanted"> div </div>  
<div>div</div>  
<p class="wanted">paragraph</p>  
<a href="">link</a>  
<a class="wanted">link</a>  
<div>div</div>  
black blue
  • 798
  • 4
  • 13