IE9 refuses to process XML response

16,146

Solution 1

IE is notoriously fussy when it comes to accepting XML and parsing it. Try something like this:

function process_xml(xml) {
  var type = $(xml).find('type').text() ;
  $('#type').html(type) ;

  // Find other elements and add them to your document
}

$(function() {
  $('#uploadForm').ajaxForm({ 
    dataType: "xml", // 'xml' passes it through the browser's xml parser
    success: function(xml,status) {

      // The SUCCESS EVENT means that the xml document
      // came down from the server AND got parsed successfully
      // using the browser's own xml parsing caps.

      process_xml(xml);

      // Everything goes wrong for Internet Explorer
      // when the mime-type isn't explicitly text/xml.

      // If you are missing the text/xml header
      // apparently the xml parse fails,
      // and in IE you don't get to execute this function AT ALL.

    },
    complete: function(xhr,status){

      if(status == 'parsererror'){

        xmlDoc = null;

        // Create the XML document from the responseText string

        if(window.DOMParser) {

          parser = new DOMParser();
          xml = parser.parseFromString(xhr.responseText,"text/xml");

        } else {

          // Internet Explorer
          xml = new ActiveXObject("Microsoft.XMLDOM");
          xml.async = "false";
          xml.loadXML(xhr.responseText);

        }

        process_xml(xml);

      }
    },
    error: function(xhr,status,error)
    {
      alert('ERROR: ' + status) ;
      alert(xhr.responseText) ;
    }
  });
});

Also,use alert() throughout debugging to provide feedback on what information is being passed through at all times.

EDIT

The crucial thing is ensure your XML file is 'well-formed', i.e. it must not contain any syntax errors. You need to begin the XML file with:

<?xml version="1.0"?>

It's not so much a server issue because, the errors come from your browser (i.e. Internet Explorer) because it thinks the XML is malformed. The error comes from your browser and indicates that your XML is malformed. You can manually set what headers you want returned with these $.ajax() settings:

dataType: ($.browser.msie) ? "text" : "xml",
accepts: {
    xml: "text/xml",
    text: "text/xml"
}

Or another way to do the same thing is to ask for a particular header:

headers: {Accept: "text/xml"},

The difference between the content-types application/xml and text/xml are minor (it's based on each XML's charset), but if you want to know you can read this post.

Solution 2

Perhaps give this a try? I use this with a google maps store locator. I notice $.parseXML actually does this internally, but its within a try/catch, and its saying your data is null (which is weird?)

      var xml;
     if (typeof data == "string") {
       xml = new ActiveXObject("Microsoft.XMLDOM");
       xml.async = false;
       xml.loadXML(data);
     } else {
       xml = data;
     }

From jQuery:

// Cross-browser xml parsing
parseXML: function( data ) {
    var xml, tmp;
    try {
        if ( window.DOMParser ) { // Standard
            tmp = new DOMParser();
            xml = tmp.parseFromString( data , "text/xml" );
        } else { // IE
            xml = new ActiveXObject( "Microsoft.XMLDOM" );
            xml.async = "false";
            xml.loadXML( data );
        }
    } catch( e ) {
        xml = undefined;
    }
    if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
        jQuery.error( "Invalid XML: " + data );
    }
    return xml;
},

Solution 3

I have used that plugin before. If I recall this right it is using an iframe to fetch the information and then it is reading the content in the iframe. The content is stored in the property responseText. But IE may have stricter rules than other browsers. Have you tried printing out the value of data.responseText?

If the value is not a XML string. I hate to say it but the API isn't made for Javascript. What I've learned is that JSONP with manipulating the script tags is the best way to do cross domain XHR. Which I don't think this plugin does.

Solution 4

js code:

    $(function() {
        $('#uploadForm').ajaxForm({
            dataType : 'xml', // OR $('#uploadResponseType option:selected').val()
            beforeSubmit : function(a, f, o) {
                $('#uploadOutput').html('Submitting...');
            },
            success : function(data) {
                var original = $(data).find('links').find('original').text();
                $('#uploadOutput').html('<img src="' + original + '" alt="" />');
            }
        });
    });

php code:

<?
    $api_key = "****************************";

    $file    = getcwd() . '/' . basename( $_FILES['image']['name'] );
    move_uploaded_file($_FILES['image']['tmp_name'], $file);

    $handle  = fopen($file, "r");
    $data    = fread($handle, filesize($file));

    $pvars   = array('image' => base64_encode($data), 'key' => $api_key);
    $post    = http_build_query($pvars);

    $curl    = curl_init();
    curl_setopt($curl, CURLOPT_URL, 'http://api.imgur.com/2/upload.xml');
    curl_setopt($curl, CURLOPT_TIMEOUT, 30);
    curl_setopt($curl, CURLOPT_POST, 1);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
    curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/x-www-form-urlencoded"));
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    $xml = curl_exec($curl); 
    curl_close ($curl);

    unlink($file);

    header('Content-type: text/xml'); 
    echo $xml;
?>
Share:
16,146
r_31415
Author by

r_31415

Updated on July 20, 2022

Comments

  • r_31415
    r_31415 almost 2 years

    This is a question in relation to this one.

    In UPDATE II, I added a script based on Jamie's feedback.

    UPDATE - tl;dr:

    I created a fiddle with a temporary key so you guys can see the problem more easily: http://jsfiddle.net/S6wEN/.

    As this question was getting too long, this is a summary.

    • I tried to use imgur API to update an image via cross domain XHR.
    • In order to abstract details in the implementation, I'm using Jquery Form Plugin (obviously, it's contained in the fiddle).
    • Works great in Chrome, Firefox, etc but it doesn't work in IE9.
    • The expected result is to update the image and retrieve image type.

    You can still find the details below.

    Thanks


    I have this HTML:

    <body>
    <form id="uploadForm" action="http://api.imgur.com/2/upload.xml" method="POST" enctype="multipart/form-data">
        <input type="hidden" name="key" value="MYKEY">
        File: <input type="file" name="image">
        Return Type: <select id="uploadResponseType" name="mimetype">
            <option value="xml">xml</option>
        </select>
        <input type="submit" value="Submit 1" name="uploadSubmitter1">
    </form>
    
    <div id="uploadOutput"></div>
    </body>
    

    So basically, I have a form to upload an image to imgur via cross domain XHR. In order to manage the nasty details, I'm using Jquery Form Plugin, which works well. However, when I try to send an image to imgur and receive an xml response, it doesn't work as expected in IE9 (I haven't tested in IE8 but I don't expect great news). It works great in Chrome and Firefox. This is the javascript part:

    (function() {
    $('#uploadForm').ajaxForm({
            beforeSubmit: function(a,f,o) {
               o.dataType = $('#uploadResponseType')[0].value;
               $('#uploadOutput').html('Submitting...');
            },
    
            complete: function(data) {
            var xmlDoc = $.parseXML( data.responseText ),
                $xml = $( xmlDoc );
                $('#uploadOutput').html($xml.find('type'));
    
            }
        });
    })();  
    

    In IE9 I receive the following errors:

    SCRIPT5022: Invalid XML: null 
    jquery.min.js, line 2 character 10890
    
    XML5619: Incorrect document syntax. 
    , line 1 character 1
    

    I also used the example given in Jquery Form Plugin's page, which uses only Javascript but it doesn't help. Obviously, the first error referring to Jquery disappears but I can't obtain the expected results (in this case, image/jpeg in the div with id="uploadOutput" ).

    When I look at the console in IE9, I get this:

    URL Method  Result  Type    Received    Taken   Initiator   Wait‎‎  Start‎‎ Request‎‎   Response‎‎  Cache read‎‎    Gap‎‎
    http://api.imgur.com/2/upload.xml   POST    200 application/xml 1.07 KB 7.89 s  click   2808    93  5351    0   0   0
    

    and as body response:

    <?xml version="1.0" encoding="utf-8"?>
    <upload><image><name/><title/><caption/><hash>xMCdD</hash>  
    <deletehash>Nb7Pvf3zPNohmkQ</deletehash><datetime>2012-03-17 01:15:22</datetime>
    <type>image/jpeg</type><animated>false</animated><width>1024</width
    <height>768</height><size>208053</size><views>0</views><bandwidth>0</bandwidth></image
    <links><original>http://i.imgur.com/xMCdD.jpg</original
    <imgur_page>http://imgur.com/xMCdD</imgur_page>
    <delete_page>http://imgur.com/delete/Nb7Pvf3zPNohmkQ</delete_page>
    <small_square>http://i.imgur.com/xMCdDs.jpg</small_square>
    <large_thumbnail>http://i.imgur.com/xMCdDl.jpg</large_thumbnail></links></upload>
    

    which is all fine, but for some reason, I can't process that information into the HTML page. I validated the XML, just to be sure that wasn't the problem. It is valid, of course.

    So, what's the problem with IE9?.

    UPDATE:

    Another way to fetch XML which works in Chrome and Firefox but not in IE9:

    (function() {
    $('#uploadForm').ajaxForm({
            dataType: "xml",
            beforeSubmit: function(a,f,o) {
               o.dataType = $('#uploadResponseType')[0].value;
               $('#uploadOutput').html('Submitting...');
            },
    
            success: function(data) {
                var $xml = $( data ),
                    element = $($xml).find('type').text();
                    alert(element);
            }
        });
    })();  
    

    UPDATE 2:

    <!DOCTYPE html>
    <html>
        <body>
        <form id="uploadForm" action="http://api.imgur.com/2/upload.xml" method="POST" enctype="multipart/form-data">
            <input type="hidden" name="key" value="00ced2f13cf6435ae8faec5d498cbbfe">
            File: <input type="file" name="image">
            Return Type: <select id="uploadResponseType" name="mimetype">
                <option value="xml">xml</option>
            </select>
            <input type="submit" value="Submit 1" name="uploadSubmitter1">
        </form>
    
        <div id="uploadOutput"></div>
        </body>
    </html>
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
    <script type="text/javascript" src="jquery.form.js"></script>
    ​<script>
    (function() {
    
        var options = { 
            // target:        '#output1',   // target element(s) to be updated with server response 
            //beforeSubmit:  showRequest,  // pre-submit callback 
            success: afterSuccess,  // post-submit callback 
            complete: afterCompletion,
            // other available options: 
            //url:       url         // override for form's 'action' attribute 
            type:      'POST',        // 'get' or 'post', override for form's 'method' attribute 
            dataType:  'xml'        // 'xml', 'script', or 'json' (expected server response type) 
            //clearForm: true        // clear all form fields after successful submit 
            //resetForm: true        // reset the form after successful submit 
    
            // $.ajax options can be used here too, for example: 
            //timeout:   3000 
        }; 
    
        function process_xml(xml) {
          var type = $(xml).find('type').text() ;
          return type;
          // Find other elements and add them to your document
        }
    
    
        function afterSuccess(responseText, statusText, xhr, $form)  { 
            // for normal html responses, the first argument to the success callback 
            // is the XMLHttpRequest object's responseText property 
    
            // if the ajaxForm method was passed an Options Object with the dataType 
            // property set to 'xml' then the first argument to the success callback 
            // is the XMLHttpRequest object's responseXML property 
    
            // if the ajaxForm method was passed an Options Object with the dataType 
            // property set to 'json' then the first argument to the success callback 
            // is the json data object returned by the server 
            var $xml = process_xml(responseText);
            console.log('success: ' + $xml);
        } 
    
    
        function afterCompletion(xhr,status){
              if(status == 'parsererror'){
    
                xmlDoc = null;
    
                // Create the XML document from the responseText string
    
                if(window.DOMParser) {
    
                  parser = new DOMParser();
                  xml = parser.parseFromString(xhr.responseText,"text/xml");
    
                } else {
    
                  // Internet Explorer
                  xml = new ActiveXObject("Microsoft.XMLDOM");
                  xml.async = "false";
                  xml.loadXML(xhr.responseText);
    
                }
    
              }
    
              console.log('complete: ' + process_xml(xhr.responseText));
        }
    
    $('#uploadForm').ajaxForm(options);
    })();  
    </script>
    

    Thanks in advance.

  • r_31415
    r_31415 about 12 years
    I think there is something wrong with the non-IE part, because now I get an uncaught exception (Invalid XML: [object Document]), but in IE9 I don't see any error, however, it doesn't do anything even if the response body shows the correct XML document.
  • r_31415
    r_31415 about 12 years
    Thanks for your answer. When I attempted to print data.responseText I got nothing in IE9 (although it works correctly in other browsers), but the response is valid XML. Furthermore, examples in the plugin documentation page work in IE9, so I'd be very surprised if this was caused by something specific to the plugin.
  • boisvert
    boisvert about 12 years
    That confirms the 'no access to iframe' hypothesis - data comes back, but can't be read.
  • r_31415
    r_31415 about 12 years
    Thanks for your effort, but maybe you didn't read the link (stackoverflow.com/questions/9695586/…). I'm looking for a cross domain XHR Javascript solution.
  • einstein
    einstein about 12 years
    The API isn't made for client code. So the only way is to fetch the XML with server side code and format it.
  • r_31415
    r_31415 about 12 years
    I think you nailed it. success() is not being called and complete() runs but obviously is not getting any response. According to your comment, it's missing the text/xml header. I checked the headers in IE and instead I see Content type: application/xml. Isn't that enough?. In any case, that's a server issue, right?.
  • hohner
    hohner about 12 years
    Does it work when you receive application/xml as the response header? If not, I've included a quick edit in my question which manually sets the response headers for the AJAX request
  • r_31415
    r_31415 about 12 years
    Well, it seems to be closer to the solution but unfortunately, adding any of those snippets provoke loading imgur.com's xml page (in Chrome, Firefox and IE). And success doesn't start.
  • r_31415
    r_31415 about 12 years
    Oh... that only happens when I added it to "beforeSubmit" function, but if I put them along with the rest as in: "success: afterSuccess, complete: afterCompletion, dataType: ($.browser.msie) ? "text" : "xml", accepts: { xml: "text/xml", text: "text/xml" }" it doesn't happen anything. By the way, <?xml version="1.0"?> is set correctly.
  • hohner
    hohner about 12 years
    Don't add the beforeStart setting, just include the settings I specified. Also, I accessed your jsFiddle using both Chrome and IE9 and both worked. I tracked the response in IE9 and it sent back application/xml with a response of 200 (i.e. it was successful). Go to Settings and enable the Developers Tools in IE9. You can track network responses by going to the Network tab and clicking 'Start capturing'. What response do you get when you send the form in IE9?
  • r_31415
    r_31415 about 12 years
    Are you sure you didn't change anything in that fiddle?. It doesn't work for me, although maybe this is what you saw. In that fiddle, I added (incorrectly) your settings to 'beforeStart', so in fiddle you get the entire xml string. But if you try it in the browser, it doesn't work (I think you get the xml file parsed by IE). Now, if I remove beforeStart and add your settings after 'type', I get this in Chrome (success: image/jpeg upload2.html:87complete: image/jpeg) which is correct and (LOG: complete:) in IE which is, of course, incorrect. Although, as you said, the response is 200.
  • hohner
    hohner about 12 years
    @RobertSmith I've just tried this again in IE9 and received the same thing. It responds with 200 Status OK and shows this in the jsFiddle window: ESnprp2HOy5OI3rILl512012-04-08 09:06:19image/jpegfalse102476829762300http://i.imgur.com/ESn‌​pr.jpghttp://imgur.c‌​om/ESnprhttp://imgur‌​.com/delete/p2HOy5OI‌​3rILl51http://i.imgu‌​r.com/ESnprs.jpghttp‌​://i.imgur.com/ESnpr‌​l.jpg, which shows that IE is parsing the XML. Using Developer Tools I can also see the unparsed XML string which is returned (as application/xml). All you need to do is define what part of the XML you want to parse on complete :)