Search code examples
xmlexceptionxmlhttprequestresponsearraybuffer

get responseXML when responseType === 'arraybuffer' after load


I am using this code to retrieve imagery data and it works.

        function imageLoadFunction (image, src) {
        var img = image.getImage();
        if (typeof window.btoa == 'function') {
            var xhr = new XMLHttpRequest();
            xhr.open('GET', 'https://cors-anywhere.herokuapp.com/' + src, true);
            xhr.setRequestHeader("Access-Control-Allow-Headers", "origin,x-requested-with");
            xhr.responseType = 'arraybuffer'; // SHOULD BE 'arraybuffer'
            xhr.onload = function(e) {
               if (this.status == 200) {
                   var uInt8Array = new Uint8Array(this.response);
                   var i = uInt8Array.length;
                   var binaryString = new Array(i);
                   while (i--) {
                       binaryString[i] = String.fromCharCode(uInt8Array[i]);
                   }
                   var data = binaryString.join('');
                   var type = xhr.getResponseHeader('content-type');
                   if (type.indexOf('image') === 0) {
                       img.src = 'data:' + type + ';base64,' + window.btoa(data);
                   }
               }
            };
            xhr.send();
        }
    };

I'd like to catch Exceptions from the (WMS) server when errors occurs, and for this I need to use responseXML. However, there seems to be two problems:

  1. the responseType is 'arraybuffer and thus responseXML says it sdhould be '' or 'document'
  2. If I try to change the responseType I receive error that I can't if request is LOADED or DONE.

Is there a way I can still use responseType === 'arraybuffer' and responseXML together?

Basically, I would need to implement the code like so (only relevant part):

if (type.indexOf('image') === 0) {
   img.src = 'data:' + type + ';base64,' + window.btoa(data);
} else {
   xmlDoc = xhr.responseXML;
   txt = "";
   x = xmlDoc.getElementsByTagName("ServiceException");
   for (i = 0; i < x.length; i++) {
       txt += x[i].childNodes[0].nodeValue + "<br>";
   }
   console.error(txt);
}

EDIT

Ok so the trick was to use String.fromCharCode()

if (type.indexOf('image') === 0) {
   img.src = 'data:' + type + ';base64,' + window.btoa(data);
} else {
   var txt = String.fromCharCode.apply(null, uInt8Array);
   console.error(txt);
}

I know it's not yet an XML but now it's much easier to treat the Exceptions.


Solution

  • The way to treat a responseType === 'arraybuffer' as an XML that I found was to make it first as a string with String.fromCharCode.apply(null, myArray); and then use a XML DOMParser on this string.

    xhr.responseType = 'arraybuffer';
    var text = String.fromCharCode.apply(null, uInt8Array);
    var xmlParser = new DOMParser();
    var asXML = xmlParser.parseFromString(exceptionAsText,"text/xml");
    // do something with response 'asXML'
    

    Good inspiration from:

    1. https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String
    2. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCharCode

    Hope this will be of help.