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']
7
  • Do you want to grab the text nodes or their (string) contents? Commented Dec 9, 2010 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) Commented Dec 9, 2010 at 13:27
  • @Sime: I want to grab the text nodes. Commented Dec 9, 2010 at 13:39
  • @user In that case the result wouldn't be ['def', 'ghi', 'jkl'] but an array of DOM Text Node objects Commented Dec 9, 2010 at 13:51
  • Seems like you might need to combine stackoverflow.com/questions/2203958/… with stackoverflow.com/questions/298750/…. Commented Dec 9, 2010 at 13:57

2 Answers 2

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);
Sign up to request clarification or add additional context in comments.

2 Comments

Instead of document.body I think I can use the common parent node of both the start node and the end node as root node.
@user375773: Indeed, I agree that would be better. I omitted that for the sake of simplicity.
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;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.