Iterating though nodes

Discussion in 'Javascript' started by matth, Nov 1, 2007.

  1. matth

    matth Guest

    I'm trying to iterate through nodes in a Selection Range, but I'm
    having a bit of trouble determining why all nodes in the range aren't
    being hit. It seems like deeply nested nodes aren't being hit for some
    reason.

    Here's the code I'm using.

    var n = startNode;
    while (n) {
    this.visited.push('[' + n.nodeName + ']');

    if (n == endNode) {
    break;
    }

    if (n != startNode && n.hasChildNodes()) {
    n = n.firstChild;
    } else {
    while (!n.nextSibling) {
    n = n.parentNode;
    }
    n = n.nextSibling;
    }
    }
    matth, Nov 1, 2007
    #1
    1. Advertising

  2. matth

    Evertjan. Guest

    matth wrote on 01 nov 2007 in comp.lang.javascript:

    > I'm trying to iterate through nodes in a Selection Range, but I'm
    > having a bit of trouble determining why all nodes in the range aren't
    > being hit. It seems like deeply nested nodes aren't being hit for some
    > reason.
    >
    > Here's the code I'm using.
    >
    > var n = startNode;
    > while (n) {
    > this.visited.push('[' + n.nodeName + ']');
    >
    > if (n == endNode) {
    > break;
    > }
    >
    > if (n != startNode && n.hasChildNodes()) {
    > n = n.firstChild;
    > } else {
    > while (!n.nextSibling) {
    > n = n.parentNode;
    > }
    > n = n.nextSibling;
    > }
    >}


    Ty this reentrant function:

    ========== test.html ========

    <body id=b>
    <div id=d1>qq</div>
    <div id=d2><div id=d21><span id=211>x</span></div>
    <div id=d22>qq</div><div id=d23>qq</div></div>
    <div id=d3>qq</div>
    </body>

    <script type='text/javascript'>

    var a = [];
    travel(document.body);
    alert(a.join('\n'))

    function travel(n){
    if (n.tagName)
    a.push(' tagName: '+n.tagName+ ' id: '+ n.id)
    if (n.firstChild)
    travel(n.firstChild)
    if (n.nextSibling)
    travel(n.nextSibling)
    }

    </script>

    =============================


    --
    Evertjan.
    The Netherlands.
    (Please change the x'es to dots in my emailaddress)
    Evertjan., Nov 1, 2007
    #2
    1. Advertising

  3. matth

    pr Guest

    matth wrote:
    > I'm trying to iterate through nodes in a Selection Range, but I'm
    > having a bit of trouble determining why all nodes in the range aren't
    > being hit. It seems like deeply nested nodes aren't being hit for some
    > reason.
    >
    > Here's the code I'm using.
    >
    > var n = startNode;
    > while (n) {
    > this.visited.push('[' + n.nodeName + ']');
    >
    > if (n == endNode) {
    > break;
    > }
    >
    > if (n != startNode && n.hasChildNodes()) {
    > n = n.firstChild;
    > } else {
    > while (!n.nextSibling) {
    > n = n.parentNode;
    > }
    > n = n.nextSibling;
    > }
    > }
    >


    Hello again. That code won't retrieve nodes that are children of the
    startNode, because you only visit firstChild for subsequent nodes. Is
    that the difficulty? Could you supply URLs of pages that fail?
    pr, Nov 1, 2007
    #3
  4. matth

    pr Guest

    Evertjan. wrote:
    > matth wrote on 01 nov 2007 in comp.lang.javascript:
    >
    >> I'm trying to iterate through nodes in a Selection Range, but I'm
    >> having a bit of trouble determining why all nodes in the range aren't
    >> being hit. It seems like deeply nested nodes aren't being hit for some
    >> reason.
    >>

    > [...]
    > <script type='text/javascript'>
    >
    > var a = [];
    > travel(document.body);
    > alert(a.join('\n'))
    >
    > function travel(n){
    > if (n.tagName)
    > a.push(' tagName: '+n.tagName+ ' id: '+ n.id)
    > if (n.firstChild)
    > travel(n.firstChild)
    > if (n.nextSibling)
    > travel(n.nextSibling)
    > }
    >
    > </script>
    >


    Nice idea, but a DOM Range can contain some distinctly un-well-formed
    HTML. We've already had some fun with this in a recent thread if you
    want to take a look.
    pr, Nov 1, 2007
    #4
  5. matth

    Evertjan. Guest

    pr wrote on 01 nov 2007 in comp.lang.javascript:

    > Evertjan. wrote:
    >> matth wrote on 01 nov 2007 in comp.lang.javascript:
    >>
    >>> I'm trying to iterate through nodes in a Selection Range, but I'm
    >>> having a bit of trouble determining why all nodes in the range
    >>> aren't being hit. It seems like deeply nested nodes aren't being hit
    >>> for some reason.
    >>>

    >> [...]
    >> <script type='text/javascript'>
    >>
    >> var a = [];
    >> travel(document.body);
    >> alert(a.join('\n'))
    >>
    >> function travel(n){
    >> if (n.tagName)
    >> a.push(' tagName: '+n.tagName+ ' id: '+ n.id)
    >> if (n.firstChild)
    >> travel(n.firstChild)
    >> if (n.nextSibling)
    >> travel(n.nextSibling)
    >> }
    >>
    >> </script>
    >>

    >
    > Nice idea, but a DOM Range can contain some distinctly un-well-formed
    > HTML.


    This 'but' is nonsense IMHO, without explanation or example.

    My code travels through the DOM-tree and documents all tagNamed nodes.

    The given base node of the travel simply is the parameter of travel().

    It does not matter if the HTML is un-well-formed, DOM nodes either have
    children and/or siblings, or they have not, and they always either have a
    parent or or they are at the top or they are not part of the DOM-tree.

    > We've already had some fun with this in a recent thread if you
    > want to take a look.


    I better don't wnat to look,
    it will spoil your passed fun,
    taking your sentence litterally. ;-)

    =====================

    Documenting the depth goes like this:

    <script type='text/javascript'>

    var a = [];
    var depth = 1;
    travel(document.body);
    alert(a.join('\n'));

    function travel(n){
    if (n.tagName)
    a.push('['+depth+'] tagName: '+n.tagName+' id: '+n.id);
    if (n.firstChild){
    depth++;
    travel(n.firstChild);
    depth--;
    };
    if (n.nextSibling)
    travel(n.nextSibling);
    };

    </script>

    --
    Evertjan.
    The Netherlands.
    (Please change the x'es to dots in my emailaddress)
    Evertjan., Nov 1, 2007
    #5
  6. matth

    matth Guest

    On Nov 1, 4:08 pm, "Evertjan." <> wrote:
    > pr wrote on 01 nov 2007 in comp.lang.javascript:
    >
    >
    >
    > > Evertjan. wrote:
    > >> matth wrote on 01 nov 2007 in comp.lang.javascript:

    >
    > >>> I'm trying to iterate through nodes in a Selection Range, but I'm
    > >>> having a bit of trouble determining why all nodes in the range
    > >>> aren't being hit. It seems like deeply nested nodes aren't being hit
    > >>> for some reason.

    >
    > >> [...]
    > >> <script type='text/javascript'>

    >
    > >> var a = [];
    > >> travel(document.body);
    > >> alert(a.join('\n'))

    >
    > >> function travel(n){
    > >> if (n.tagName)
    > >> a.push(' tagName: '+n.tagName+ ' id: '+ n.id)
    > >> if (n.firstChild)
    > >> travel(n.firstChild)
    > >> if (n.nextSibling)
    > >> travel(n.nextSibling)
    > >> }

    >
    > >> </script>

    >
    > > Nice idea, but a DOM Range can contain some distinctly un-well-formed
    > > HTML.

    >
    > This 'but' is nonsense IMHO, without explanation or example.
    >
    > My code travels through the DOM-tree and documents all tagNamed nodes.
    >
    > The given base node of the travel simply is the parameter of travel().
    >
    > It does not matter if the HTML is un-well-formed, DOM nodes either have
    > children and/or siblings, or they have not, and they always either have a
    > parent or or they are at the top or they are not part of the DOM-tree.
    >
    > > We've already had some fun with this in a recent thread if you
    > > want to take a look.

    >
    > I better don't wnat to look,
    > it will spoil your passed fun,
    > taking your sentence litterally. ;-)
    >
    > =====================
    >
    > Documenting the depth goes like this:
    >
    > <script type='text/javascript'>
    >
    > var a = [];
    > var depth = 1;
    > travel(document.body);
    > alert(a.join('\n'));
    >
    > function travel(n){
    > if (n.tagName)
    > a.push('['+depth+'] tagName: '+n.tagName+' id: '+n.id);
    > if (n.firstChild){
    > depth++;
    > travel(n.firstChild);
    > depth--;
    > };
    > if (n.nextSibling)
    > travel(n.nextSibling);
    >
    > };
    >
    > </script>
    >
    > --
    > Evertjan.
    > The Netherlands.
    > (Please change the x'es to dots in my emailaddress)


    Thank you both for your help.
    I'm going to include the full bookmarklet code I'm using.
    A specific instance that fails is when I select the links and image
    typically present at the top of drudgereport.com (the stuff right
    above Drudge's header graphic).

    I'll try implementing your code Evertjan, and report back.

    javascript:({
    visited: [],
    iterate: function(r, startNode, endNode) {
    var n = startNode;
    var sel = window.getSelection().toString();
    var text = null;
    while (n) {
    if ((n == r.startContainer || n == r.endContainer) && n.nodeType ==
    3) {
    if (r.startContainer == r.endContainer) {
    text = n.nodeValue.substring(r.startOffset, r.endOffset);
    } else if (n == r.startContainer) {
    text = n.nodeValue.substring(r.startOffset);
    } else if (n == r.endContainer) {
    text = n.nodeValue.substring(0, r.endOffset);
    }
    } else if (n.nodeType == 3) {
    text = n.nodeValue;
    }

    this.visited.push('[' + n.nodeName + ']: ' + (n.nodeType == 3 &&
    text != null ? text : ''));
    text = null;

    if (n == endNode) {
    break;
    }

    if (n.hasChildNodes()) {
    n = n.firstChild;
    } else if (n.nextSibling){
    n = n.nextSibling;
    } else {
    n = n.parentNode.nextSibling;
    }
    }
    },
    go: function(r) {
    this.iterate(r, r.startContainer, r.endContainer);
    var w = window.open(), d = w.document;
    var sel = window.getSelection().toString();
    d.write(this.visited.join('<br>'));
    d.write("<br><br>Selection:<br>" + sel);
    d.close();
    }
    }).go(window.getSelection().getRangeAt(0));
    matth, Nov 3, 2007
    #6
  7. matth

    pr Guest

    matth wrote:
    > Thank you both for your help.
    > I'm going to include the full bookmarklet code I'm using.
    > A specific instance that fails is when I select the links and image
    > typically present at the top of drudgereport.com (the stuff right
    > above Drudge's header graphic).
    >
    > I'll try implementing your code Evertjan, and report back.
    >

    [...]

    Here's my latest take on the question (another bookmarklet), which you
    may find useful. As far as I'm aware, it lists all the nodes beneath a
    range's commonAncestorContainer, but the bug is that (so far) it doesn't
    indicate whether it's arriving at a node or leaving it. Still, it does
    show a couple of things missing in your code:

    - child offsets of the startContainer and endContainer when the parent
    is an element object or another node having children.

    - a slightly different approach to ascending node ancestors in
    search of nextSibling (your version quits if there is no
    parentNode.nextSibling).

    - escaped debug output! This may explain the funny things at Drudge
    Report (a couple of <noscript>'s in there).

    See what you think...


    javascript:

    function RangeIterator() {
    this.onNode = function (str, node) {}; /* default function: supply
    your own */
    this.iterate = function (r) {
    var me = this, node = r.startContainer, offset = r.startOffset,
    finalNode = r.endContainer, finalOffset = r.endOffset;

    function visitNode(node, offset) {
    var isFinal = (node == finalNode), lastChildIndex, i, c,
    text = '';

    switch (node.nodeType) {
    case 3: /* text, CDATA, processing instruction, comment */
    case 4:
    case 7:
    case 8:
    text = node.nodeValue;

    if (isFinal) {
    text = text.substring(0, finalOffset);
    }
    if (offset) {
    text = text.substring(offset);
    }
    me.onNode(text, node);
    break;
    default:
    me.onNode(text, node);
    lastChildIndex = isFinal ? finalOffset :
    node.childNodes.length;

    for (i = offset, c = node.childNodes.item(i);
    i < lastChildIndex;
    c = c.nextSibling, i++) {
    if (!visitNode(c, 0)) {
    return false;
    }
    }
    }
    return !isFinal;
    }
    /* end function */

    while (visitNode(node, offset)) {
    if (!node.nextSibling) {
    node = node.parentNode;
    /* doesn't indicate when it's leaving an incompletely
    selected node */
    offset = node.childNodes.length;
    } else {
    node = node.nextSibling;
    offset = 0;
    }
    }
    return true;
    };
    }
    /* for testing: */
    ({
    iterator: new RangeIterator(),
    visited: [],
    toHTML: function (a) {
    return ['&lt;', '&gt;', '&amp;']['<>&'.indexOf(a)];},
    go: function () {
    var timer, w = window, s = w.getSelection(), i, wd, me = this;

    this.iterator.onNode = function (str, node) {
    me.visited.push(node.nodeName + ': ' + str);};
    timer = +new Date();
    if (s.rangeCount && this.iterator.iterate(s.getRangeAt(0))) {
    w.alert(this.visited.length + ' node(s) visited in ' +
    (+new Date() - timer) + ' ms.');

    for (i = this.visited.length; i--; ) {
    this.visited = this.visited.replace(/[<>&]/g,
    this.toHTML);
    }

    w = window.open();
    wd = w.document;
    wd.write(this.visited.join('<br>'));
    wd.close();
    } else {
    w.alert("No selection");
    }
    }
    }).go();
    pr, Nov 5, 2007
    #7
  8. matth

    matth Guest

    On Nov 5, 2:20 pm, pr <> wrote:
    > matth wrote:
    > > Thank you both for your help.
    > > I'm going to include the full bookmarklet code I'm using.
    > > A specific instance that fails is when I select the links and image
    > > typically present at the top of drudgereport.com (the stuff right
    > > above Drudge's header graphic).

    >
    > > I'll try implementing your code Evertjan, and report back.

    >
    > [...]
    >
    > Here's my latest take on the question (another bookmarklet), which you
    > may find useful. As far as I'm aware, it lists all the nodes beneath a
    > range's commonAncestorContainer, but the bug is that (so far) it doesn't
    > indicate whether it's arriving at a node or leaving it. Still, it does
    > show a couple of things missing in your code:
    >
    > - child offsets of the startContainer and endContainer when the parent
    > is an element object or another node having children.
    >
    > - a slightly different approach to ascending node ancestors in
    > search of nextSibling (your version quits if there is no
    > parentNode.nextSibling).
    >
    > - escaped debug output! This may explain the funny things at Drudge
    > Report (a couple of <noscript>'s in there).
    >
    > See what you think...
    >
    > javascript:
    >
    > function RangeIterator() {
    > this.onNode = function (str, node) {}; /* default function: supply
    > your own */
    > this.iterate = function (r) {
    > var me = this, node = r.startContainer, offset = r.startOffset,
    > finalNode = r.endContainer, finalOffset = r.endOffset;
    >
    > function visitNode(node, offset) {
    > var isFinal = (node == finalNode), lastChildIndex, i, c,
    > text = '';
    >
    > switch (node.nodeType) {
    > case 3: /* text, CDATA, processing instruction, comment */
    > case 4:
    > case 7:
    > case 8:
    > text = node.nodeValue;
    >
    > if (isFinal) {
    > text = text.substring(0, finalOffset);
    > }
    > if (offset) {
    > text = text.substring(offset);
    > }
    > me.onNode(text, node);
    > break;
    > default:
    > me.onNode(text, node);
    > lastChildIndex = isFinal ? finalOffset :
    > node.childNodes.length;
    >
    > for (i = offset, c = node.childNodes.item(i);
    > i < lastChildIndex;
    > c = c.nextSibling, i++) {
    > if (!visitNode(c, 0)) {
    > return false;
    > }
    > }
    > }
    > return !isFinal;
    > }
    > /* end function */
    >
    > while (visitNode(node, offset)) {
    > if (!node.nextSibling) {
    > node = node.parentNode;
    > /* doesn't indicate when it's leaving an incompletely
    > selected node */
    > offset = node.childNodes.length;
    > } else {
    > node = node.nextSibling;
    > offset = 0;
    > }
    > }
    > return true;
    > };
    > }
    > /* for testing: */
    > ({
    > iterator: new RangeIterator(),
    > visited: [],
    > toHTML: function (a) {
    > return ['&lt;', '&gt;', '&amp;']['<>&'.indexOf(a)];},
    > go: function () {
    > var timer, w = window, s = w.getSelection(), i, wd, me = this;
    >
    > this.iterator.onNode = function (str, node) {
    > me.visited.push(node.nodeName + ': ' + str);};
    > timer = +new Date();
    > if (s.rangeCount && this.iterator.iterate(s.getRangeAt(0))) {
    > w.alert(this.visited.length + ' node(s) visited in ' +
    > (+new Date() - timer) + ' ms.');
    >
    > for (i = this.visited.length; i--; ) {
    > this.visited = this.visited.replace(/[<>&]/g,
    > this.toHTML);
    > }
    >
    > w = window.open();
    > wd = w.document;
    > wd.write(this.visited.join('<br>'));
    > wd.close();
    > } else {
    > w.alert("No selection");
    > }
    > }
    > }).go();


    Don't think I'm ignoring you! I'm doing my best. You threw up a Hail
    Mary there, I'm going to need a minute to catch up. :)
    matth, Nov 8, 2007
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. asd
    Replies:
    3
    Views:
    429
    Arnaud Berger
    May 23, 2005
  2. gavnosis
    Replies:
    0
    Views:
    500
    gavnosis
    Aug 2, 2003
  3. Timo Nentwig

    selecting nodes between other nodes

    Timo Nentwig, Jun 16, 2004, in forum: XML
    Replies:
    1
    Views:
    393
    Patrick TJ McPhee
    Jun 17, 2004
  4. Johnny Ooi

    Looking A Nodes From Within Nodes

    Johnny Ooi, Nov 13, 2004, in forum: XML
    Replies:
    10
    Views:
    646
    Johnny Ooi
    Nov 14, 2004
  5. carl
    Replies:
    5
    Views:
    2,336
    James Kanze
    Nov 25, 2009
Loading...

Share This Page