Asked  7 Months ago    Answers:  5   Viewed   23 times

Is there any way to get the collection of all textNode objects within a document?

getElementsByTagName() works great for Elements, but textNodes are not Elements.

Update: I realize this can be accomplished by walking the DOM - as many below suggest. I know how to write a DOM-walker function that looks at every node in the document. I was hoping there was some browser-native way to do it. After all it's a little strange that I can get all the <input>s with a single built-in call, but not all textNodes.

 Answers

86

Update:

I have outlined some basic performance tests for each of these 6 methods over 1000 runs. getElementsByTagName is the fastest but it does a half-assed job, as it does not select all elements, but only one particular type of tag ( i think p) and blindly assumes that its firstChild is a text element. It might be little flawed but its there for demonstration purpose and comparing its performance to TreeWalker. Run the tests yourselves on jsfiddle to see the results.

  1. Using a TreeWalker
  2. Custom Iterative Traversal
  3. Custom Recursive Traversal
  4. Xpath query
  5. querySelectorAll
  6. getElementsByTagName

Let's assume for a moment that there is a method that allows you to get all Text nodes natively. You would still have to traverse each resulting text node and call node.nodeValue to get the actual text as you would do with any DOM Node. So the issue of performance is not with iterating through text nodes, but iterating through all nodes that are not text and checking their type. I would argue (based on the results) that TreeWalker performs just as fast as getElementsByTagName, if not faster (even with getElementsByTagName playing handicapped).

Ran each test 1000 times.

Method                  Total ms        Average ms
--------------------------------------------------
document.TreeWalker          301            0.301
Iterative Traverser          769            0.769
Recursive Traverser         7352            7.352
XPath query                 1849            1.849
querySelectorAll            1725            1.725
getElementsByTagName         212            0.212

Source for each method:

TreeWalker

function nativeTreeWalker() {
    var walker = document.createTreeWalker(
        document.body, 
        NodeFilter.SHOW_TEXT, 
        null, 
        false
    );

    var node;
    var textNodes = [];

    while(node = walker.nextNode()) {
        textNodes.push(node.nodeValue);
    }
}

Recursive Tree Traversal

function customRecursiveTreeWalker() {
    var result = [];

    (function findTextNodes(current) {
        for(var i = 0; i < current.childNodes.length; i++) {
            var child = current.childNodes[i];
            if(child.nodeType == 3) {
                result.push(child.nodeValue);
            }
            else {
                findTextNodes(child);
            }
        }
    })(document.body);
}

Iterative Tree Traversal

function customIterativeTreeWalker() {
    var result = [];
    var root = document.body;

    var node = root.childNodes[0];
    while(node != null) {
        if(node.nodeType == 3) { /* Fixed a bug here. Thanks @theazureshadow */
            result.push(node.nodeValue);
        }

        if(node.hasChildNodes()) {
            node = node.firstChild;
        }
        else {
            while(node.nextSibling == null && node != root) {
                node = node.parentNode;
            }
            node = node.nextSibling;
        }
    }
}

querySelectorAll

function nativeSelector() {
    var elements = document.querySelectorAll("body, body *"); /* Fixed a bug here. Thanks @theazureshadow */
    var results = [];
    var child;
    for(var i = 0; i < elements.length; i++) {
        child = elements[i].childNodes[0];
        if(elements[i].hasChildNodes() && child.nodeType == 3) {
            results.push(child.nodeValue);
        }
    }
}

getElementsByTagName (handicap)

function getElementsByTagName() {
    var elements = document.getElementsByTagName("p");
    var results = [];
    for(var i = 0; i < elements.length; i++) {
        results.push(elements[i].childNodes[0].nodeValue);
    }
}

XPath

function xpathSelector() {
    var xpathResult = document.evaluate(
        "//*/text()", 
        document, 
        null, 
        XPathResult.ORDERED_NODE_ITERATOR_TYPE, 
        null
    );

    var results = [], res;
    while(res = xpathResult.iterateNext()) {
        results.push(res.nodeValue);  /* Fixed a bug here. Thanks @theazureshadow */
    }
}

Also, you might find this discussion helpful - http://bytes.com/topic/javascript/answers/153239-how-do-i-get-elements-text-node

Tuesday, June 1, 2021
 
buymypies
answered 7 Months ago
72

If you have a specific node (of type #text) and want to change its value you can use the nodeValue property:

node.nodeValue="new value";

Note:

innerText (and possibly textContent) will return/set both the current node and all descendent nodes text, and so may not be the behaviour you want/expect.

Wednesday, July 28, 2021
 
mgraph
answered 5 Months ago
43

Here is an example to expand the first loop , see it here : http://codepad.org/cn0UFPrD

rows = [[1,2,3,4],[3,5,88,9],[4,55,-6,0],[0,34,22,1222]]
t1 = [(min([row[i] for row in rows]),max([row[i] for row in rows])) for i in range(len(rows[0]))]
print(t1)

# Easy loop
t2 = []
for i in range(len(rows[0])):
    innerElements = []
    for row in rows:
        innerElements.append(row[i])
    newTuple = ( min(innerElements),max(innerElements) )
    t2.append(newTuple)

print(t2)

You can expand the second loop the same way.

Friday, November 19, 2021
 
k to the z
answered 3 Weeks ago
55

Text inside <script> tags has only one thing in common: their parent is a <script> element.

if (node.parentNode.nodeName !== 'SCRIPT')

Another approach is to use the filter:

var rejectScriptTextFilter = {
  acceptNode: function(node) {
    if (node.parentNode.nodeName !== 'SCRIPT') {
      return NodeFilter.FILTER_ACCEPT;
    }
  }
};

var walker = document.createTreeWalker(
  document.body, 
  NodeFilter.SHOW_TEXT, 
  rejectScriptTextFilter,
  false
);

var node;
var textNodes = [];

while(node = walker.nextNode()) {
  textNodes.push(node.nodeValue);
}

console.log(textNodes);
<script> var str = "script here"; </script>
<p> text here </p>
Wednesday, November 24, 2021
 
Koerr
answered 2 Weeks ago
93

I removed the form=unformatted part of the open statement and it got through that part no problem.

I received a different error after fixing the above. After allocating the variables, you try reading from the file without rewinding it. That is, the program last left the file at at the end, so there isn't anything more to read when you try to read it. The fix is simple: tell the program to jump back up to the beginning by using rewind:

allocate(jobs(nr))
rewind(10)
do i=1,nr
   read(10,*) ...
enddo
Friday, December 3, 2021
 
M. Dudley
answered 4 Days ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share