Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript webworker won't load XML file via XMLHttpRequest

I'm am strugling to get a webworker to load an XML file from the same domain on the side of my main page, any help would be greatly appreciated.

function readXML(){
 var xhr = new XMLHttpRequest(); //Only for FF
 xhr.open("GET","../db/pointer.xml",true);
 xhr.send(null);
 xhr.onreadystatechange = function(e){

 if(xhr.status == 200 && xhr.readyState == 4){
    //Post back info to main page
    postMessage(xhr.responseXML.getElementsByTagName("value").length);
 }
}

When this runs in a script tag on the main page, i get a 3. When running thru the WebWorker, FireBug gives me

hr.responseXML is null

postMessage(xhr.responseXML.getElementsByTagName("value").length);

In the FireBug console, GET Request responded with

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <value>A value</value>
    <value>Another Value</value>
    <value>A third Value</value>
</root>

So the response is correct but i cannot figure out where it's going wrong. If i change responseXML to responseText the worker outputs

A value Another Value A third Value

Which is correct! why won't the script open it as an XML document?

UPDATE

function readXML(){
 var xhr = new XMLHttpRequest(); //Only for FF
 xhr.open("GET","../db/pointer.xml",false);
 xmlhttp.setRequestHeader('Content-Type',  'text/xml');
 xhr.overrideMimeType('text/xml');
 xhr.send(null);
 xhr.onreadystatechange = function(e){

 if(xhr.status == 200 && xhr.readyState == 4){
    //Post back info to main page
    postMessage(xhr.responseXML.getElementsByTagName("value").length);
 }
}

When setRequestHeader & overrideMimeType is changed, the onreadystatechange never fires, doesn't matter if status and readyState are there or not, it won't run. If i remove the onreadystatechange completely and just run xhr.responseXML, i get the null error again.

I still get the correct XML in as response in the console, is this a webworker issue instead of a httprequest problem? Getting desperate here :)

index.html http://www.axlonline.se/worker/index.html
worker.js http://www.axlonline.se/worker/worker.js

like image 771
axlOnline Avatar asked Jan 30 '12 23:01

axlOnline


2 Answers

According to the standard, Web workers can have not have access to any type of DOM manipulation.

The DOM APIs (Node objects, Document objects, etc) are not available to workers in this version of this specification.

responseXML and channel properties are always null from an ajax request as the parsing of the XML is a DOM API. No matter the request and response headers there will be no way of getting requestXML unless you manually parse it.

like image 140
georgephillips Avatar answered Nov 18 '22 05:11

georgephillips


Had the same Problem. Apparently XML parsing is not possible in webworkers. I used sax.js to parse a XML on web worker. https://github.com/isaacs/sax-js

this is basicly my parser.

function xmlParser(strict){
    this.parser = sax.parser(strict, {lowercase:true});
}

xmlParser.prototype.parseFile = function(file, callback){
    var _this = this;
    $.ajax.get({
        cache: false,
        url: file,
        dataType: "xml",
        success: function(data){
            var dom = _this.parseText(data.text);
            callback( dom );
        },
        error: function(data){
        }
    });
}

xmlParser.prototype.parseText = function(xlmText){
    var dom = undefined;
    var activeNode = dom;

    this.parser.onerror = function (e) { };
    this.parser.onend = function () {};

    this.parser.ontext = function (t) {
        if(activeNode != undefined)
            activeNode.Text = t;
    };
    this.parser.onopentag = function (node) {
        var node = new xmlNode(node.name, activeNode, node.attributes, dom);
        if(dom === undefined){
            dom = node;
            activeNode = node;
        }else{
            activeNode.Children.push(node);
            activeNode = node;
        }
    };
    this.parser.onclosetag = function (node) {
        activeNode = activeNode.Parent;
    };

    this.parser.write(xlmText).close();
    return dom;
}

xmlNode enables a jquery like handling of the tree.

function xmlFilterResult(){
    this.length = 0;
}

xmlFilterResult.prototype.push = function(element){
    this[this.length++] = element;
}

xmlFilterResult.prototype.attr = function(atribute){
    if(this.length == 0)
        return '';
    return this[0].Attributes[atribute];
}
xmlFilterResult.prototype.text = function(atribute){
    if(this.length == 0)
        return '';
    return this[0].Text;
}

xmlFilterResult.prototype.children = function(search, result){
    if(result == undefined)
        result = new xmlFilterResult();
    if(search == undefined){
        for(var i = 0; i < this.length; i++){
            this[i].children(search, result);
        }
    }else{
        this.find(search, true, result);
    }
    return result;
}
xmlFilterResult.prototype.find = function(search, nonrecursive, result){
    if(result == undefined)
        result = new xmlFilterResult();
    if(search.charAt(0) == '.')
        return this.findAttr('class', search.substring(1), nonrecursive, result);
    else if(search.charAt(0) == '#')
        return this.findAttr('id', search.substring(1), nonrecursive, result);
    else
        return this.findName(search, nonrecursive, result);
}
xmlFilterResult.prototype.findAttr = function(attr, value, nonrecursive, result){
    if(result == undefined)
        result = new xmlFilterResult();
    var child;
    for(var i = 0; i < this.length; i++){
        child = this[i];
        child.findAttr(attr, value, nonrecursive, result);
    }
    return result
}
xmlFilterResult.prototype.findName = function(name, nonrecursive, result){
    if(result == undefined)
        result = new xmlFilterResult();
    var child;
    for(var i = 0; i < this.length; i++){
        child = this[i];
        child.findName(name, nonrecursive, result);
    }
    return result
}
// xmlFilterResult.prototype.findID = function(id, nonrecursive){
    // var child, result = new xmlFilterResult();
    // for(var i = 0; i < this.length; i++){
        // child = this[i];
        // child.findID(id, nonrecursive, result);
    // }
    // return result
// }




function xmlNode(name, parent, atributes, root){
    this.Name = name;
    this.Children = [];
    this.Parent = parent;
    this.Attributes = atributes;
    this.Document = root;
    this.Text = '';
}

xmlNode.prototype.attr = function(atribute){
    return this.Attributes[atribute];
}
xmlNode.prototype.text = function(atribute){
    return this.Text;
}

xmlNode.prototype.children = function(search, result){
    if(result == undefined)
        result = new xmlFilterResult();
    if(search == undefined){
        for(i in this.Children)
            result.push(this.Children[i]);
    }else{
        return this.find(search, true, result);
    }
    return result;
}
xmlNode.prototype.find = function(search, nonrecursive, result){
    if(search.charAt(0) == '.')
        return this.findAttr('class', search.substring(1), nonrecursive, result);
    else if(search.charAt(0) == '#')
        return this.findAttr('id', search.substring(1), nonrecursive, result);
    else
        return this.findName(search, nonrecursive, result);
}
xmlNode.prototype.findAttr = function(attr, value, nonrecursive, result){
    var child, i;
    if(result == undefined)
        result = new xmlFilterResult();
    for(i in this.Children){
        child = this.Children[i];
        if(child.Attributes[attr] == value)
            result.push(child);
        if(!nonrecursive)
            child.findAttr(attr, value, nonrecursive, result);
    }
    return result
}
xmlNode.prototype.findName = function(name, nonrecursive, result){
    var child, i;
    if(result == undefined)
        result = new xmlFilterResult();
    for(i in this.Children){
        child = this.Children[i];
        if(child.Name == name){
            result.push(child);
        }
        if(!nonrecursive)
            child.findName(name, nonrecursive, result);
    }
    return result
}

Its nothing special but you get the idea of that to do.

like image 40
Bellian Avatar answered Nov 18 '22 05:11

Bellian