Discussions » Development

Xpath iterateNext fails in Firefox

§
Posted: 2016-10-23
Edited: 2016-10-23

Xpath iterateNext fails in Firefox

Why does this the code below fail in firefox

Updated

 var iterator = document.evaluate("*", document.body, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
    var count = 0;
    var el = iterator.iterateNext();
    while (el)
    {
        count++;
        el.style.backgroundColor = "red"; //Settings this makes it fail in iteration. if I remove this line, it's fine.
        try
        {
            el = iterator.iterateNext();
        }
        catch (e)
        {
            console.log(e.message);
            el = null;
        }
    }
    console.warn(count);

It only prints out the first element. If I remove the setting of backgroundColor it loops through the whole list of elements.

Outlog log value for count is 1, and if I comment out line 7 the count is 6

The error displayed is: An attempt was made to use an object that is not, or is no longer, usable

wOxxOmMod
§
Posted: 2016-10-23

Maybe it's a bug in particular Firefox versions? Anyway, I would use the much much much faster document.body.getElementsByTagName('*')

§
Posted: 2016-10-23
Edited: 2016-10-23

Thanks. That was a quick re-code of the issue. I updated the first post.

The problem still exists. It seems if I edit the element, xpath iterator breaks with the following message

`An attempt was made to use an object that is not, or is no longer, usable`

Just tried it again and now it does not work at all in chrome, whether I comment line 7 or not.

I could use document.getElementByTag("*") to return everything but I wish to avoid it and use xpath to return elements with "resize" attribute. The querySelector is not an option as I do not want a snap shot.

It seems I will have to use the getElementByTag("*") solution.

Still a very unexpected behaviour. Am I not allowed to alter the elements attributes?

wOxxOmMod
§
Posted: 2016-10-23

Hmm... Let's see. The attribute changes outerHTML, that is the element itself as a whole so to speak. Maybe it breaks this ordered xpath mode? Anyway, it looks like a bug.

§
Posted: 2016-10-23
Edited: 2016-10-23

Hmm... Let's see. The attribute changes outerHTML, that is the element itself as a whole so to speak. Maybe it breaks this ordered xpath mode? Anyway, it looks like a bug.

Is adding an attribute or changing its value a modification of "the document tree"?

Note however, that if the document is mutated (the document tree is modified) between iterations that will invalidate the iteration and the invalidIteratorState property of XPathResult is set to true, and a NS_ERROR_DOM_INVALID_STATE_ERR exception is thrown.

https://developer.mozilla.org/docs/Introduction_to_using_XPath_in_JavaScript#Node-Set_Types

Seems like a very fragile object.

§
Posted: 2016-10-24

I don't understand what is the problem with getElementsByTagName or even with querySelectorAll('*[resize]').

This code works better than the example and without problems in FF and GC:

 var elems = document.body.getElementsByTagName('*');
 for (var count = 0; count < elems.length; count++)
 {
   elems[count].style.backgroundColor = 'red';
 }
 console.warn(count);

The only problem I can see is that resize can be a property without being an attribute, i.e. when you set this value in a stylesheet rule. In that case, you must get all items and then check wich one has el.style.resize.

Maybe I don't understand anything and my comment is a piece of shit. Sorry if so. Can anyone bring me light here?

§
Posted: 2016-10-24

Hmm... Let's see. The attribute changes outerHTML, that is the element itself as a whole so to speak. Maybe it breaks this ordered xpath mode? Anyway, it looks like a bug.

Is adding an attribute or changing its value a modification of "the document tree"?
Note however, that if the document is mutated (the document tree is modified) between iterations that will invalidate the iteration and the invalidIteratorState property of XPathResult is set to true, and a NS_ERROR_DOM_INVALID_STATE_ERR exception is thrown.
https://developer.mozilla.org/docs/Introduction_to_using_XPath_in_JavaScript#Node-Set_Types

Seems like a very fragile object.

Very fragile indeed. Thanks.

@leoncastro

My code was an example. The actual script tries to only edit elements with the "resize" attribute only, everything else returned is not wanted. So basically now my code will have to check if it has resize attribute before altering.

§
Posted: 2016-10-25

But you can still use my example

var elems = document.body.getElementsByTagName('*');
for (var count = 0; count < elems.length; count++)
{
  if (elems[count].style.resize)
    elems[count].style.backgroundColor = 'red';
}
console.warn(count);

isn't ?

§
Posted: 2016-10-25

The alternative solution was not an issue. I just wanted to figure out why it wasn't working, because it bugged me. :wink:

It seems I will have to use the getElementByTag("*") solution.
§
Posted: 2016-10-25

Understood.
I had thought that there was some problem with getElementByTag.
Thank you for the clarification.

Post reply

Sign in to post a reply.