2

Is there any way of getting some sort of XPATH for each word which matches a given regular expression? I mean the words displayed by the navigator to the user. That way I could manipulate the HTML corresponding to each word individually.

mochomecha
  • 162
  • 1
  • 11
  • 1
    The easiest solution I can think of would be using jQuery's [`:contains()`](https://api.jquery.com/contains-selector/) selector. Of course, that's only if you're using jQuery. – Hatchet Feb 03 '16 at 16:30
  • 1
    Visible as opposed to what? What do you mean by "DOM path"? Do you mean an XPath-type expression? What are you planning to do with it? By the way, pieces of text, such as a word, are not addressable by any means, whether it be a XPath or a CSS selector. Both address only **elements**. –  Feb 03 '16 at 16:33
  • @torazaburo yes, I mean that. What if I parse the words, and convert them to elements? Would that be too time-consuming? – mochomecha Feb 03 '16 at 16:43
  • Turning words and phrases into their own HTMl elements is a different problem; there are quite a few questions here on SO about that, which I am sure you would find if you searched. –  Feb 03 '16 at 16:50

2 Answers2

1

There's not a unique XPath to a node, but here's a solution that uses the function cssPath from this answer to return the CSS path of an element that contains text matching a regex.

var cssPath = function(el) {
  if (!(el instanceof Element))
    return;
  var path = [];
  while (el.nodeType === Node.ELEMENT_NODE) {
    var selector = el.nodeName.toLowerCase();
    if (el.id) {
      selector += '#' + el.id;
      path.unshift(selector);
      break;
    } else {
      var sib = el,
        nth = 1;
      while (sib = sib.previousElementSibling) {
        if (sib.nodeName.toLowerCase() == selector)
          nth++;
      }
      if (nth != 1)
        selector += ":nth-of-type(" + nth + ")";
    }
    path.unshift(selector);
    el = el.parentNode;
  }
  return path.join(" > ");
}

var startElem = document.body;
var items = startElem.getElementsByTagName("*");
for (var i = items.length; i--;) {
  var match = items[i].innerHTML.match(/fox/);
  if (match) {
    var matched = document.createElement('div');
    matched.innerHTML = cssPath(items[i]);
    document.getElementById("matches").appendChild(matched);
  }
}
<div>The quick brown fox</div>
<div>jumped over the lazy dog.</div>
<div>The slow orange ocelot</div>
<div>crawled under the quick fox.</div>
<hr>
<h4>Matches /fox/</h4>
<div id="matches"></div>
Community
  • 1
  • 1
rphv
  • 5,409
  • 3
  • 29
  • 47
0

My solution: In the DOM, I put each word in a newly created span element.

<span id="foundword1">
word1
</span>

<span id="foundword2">
word2
</span>
mochomecha
  • 162
  • 1
  • 11