9

Given the following HTML-Fragment:

<div>
  <p>
    abc <span id="x">[</span> def <br /> ghi
  </p>
  <p>
    <strong> jkl <span id="y">]</span> mno </strong>
  </p>
</div>

I need an algorithm to fetch all nodes of type Text between #x and #y with Javascript. Or is there a JQuery function that does exactly that?

The resulting Text nodes (whitespace nodes ignored) for the example above would then be:

['def', 'ghi', 'jkl']
Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
Martin Andert
  • 93
  • 1
  • 5
  • Do you want to grab the text nodes or their (string) contents? – Šime Vidas Dec 09 '10 at 13:24
  • Also, note that there are more than 3 text nodes between those two SPANs. (I think 5, but I'm not sure) – Šime Vidas Dec 09 '10 at 13:27
  • @Sime: I want to grab the text nodes. – Martin Andert Dec 09 '10 at 13:39
  • @user In that case the result wouldn't be `['def', 'ghi', 'jkl']` but an array of DOM Text Node objects – Šime Vidas Dec 09 '10 at 13:51
  • What's your final goal? Find the text between [ and ]? – Shadow The GPT Wizard Dec 09 '10 at 14:25
  • @ShadowWizard The final goal is to highlight the text between the two anchor nodes by wrapping the text nodes in span elements which have a certain css class that sets a background color. Much like selecting some text on a webpage and saving this selection for later reference. – Martin Andert Dec 11 '10 at 22:56
  • Seems like you might need to combine https://stackoverflow.com/questions/2203958/jquery-recursive-iteration-over-objects with https://stackoverflow.com/questions/298750/how-do-i-select-text-nodes-with-jquery. – sje397 Dec 09 '10 at 13:57

2 Answers2

11

The following works in all major browsers using DOM methods and no library. It also ignores whitespace text nodes as mentioned in the question.

Obligatory jsfiddle: http://jsfiddle.net/timdown/a2Fm6/

function getTextNodesBetween(rootNode, startNode, endNode) {
    var pastStartNode = false, reachedEndNode = false, textNodes = [];

    function getTextNodes(node) {
        if (node == startNode) {
            pastStartNode = true;
        } else if (node == endNode) {
            reachedEndNode = true;
        } else if (node.nodeType == 3) {
            if (pastStartNode && !reachedEndNode && !/^\s*$/.test(node.nodeValue)) {
                textNodes.push(node);
            }
        } else {
            for (var i = 0, len = node.childNodes.length; !reachedEndNode && i < len; ++i) {
                getTextNodes(node.childNodes[i]);
            }
        }
    }

    getTextNodes(rootNode);
    return textNodes;
}

var x = document.getElementById("x"),
    y = document.getElementById("y");

var textNodes = getTextNodesBetween(document.body, x, y);
console.log(textNodes);
Tim Down
  • 318,141
  • 75
  • 454
  • 536
0

The following example uses jQuery to find any two elements that are next to each other and may or may not have text nodes between them. This foreach loop will check the resulted elements to find any text nodes and add them to the list.

function getTextNodes() {
    var list = [];
    $(document.body).find("*+*").toArray().forEach(function (el) {
        var prev = el.previousSibling;
        while (prev != null && prev.nodeType == 3) {
            list.push(prev);
            prev = prev.previousSibling;
        }
    });
    return list;
}
Dan-el
  • 53
  • 4