I have a javascript which receives info from a servlet using jQuery:
$.get("authenticate", {badge:$('input#badge').val()}, function(data) {
console.log("xml: "+data);
displayInfoReturn(data);
});
When I process the result in Safari, everything works great:
function displayInfoReturn(data) {
if (/load/.test(data)) { // ...process string
}
}
But the 'if' always returns false in firefox (haven't tried it yet in IE or Chrome). I also tried using indexOf != -1 and search != -1. Nothing works!
One curious thing I noticed however is when I print data to console:
console.log ("received... "+data);
it comes back with "received... [object XMLDocument]". So apparently it's not treating my data as a string. I tried data.toString() but that doesn't work either. So how can I get firefox to play fair here?
What does your servlet return? An application/xml document or just text/plain? What have you set in response.setContentType()? You seem to be expecting XML and Firefox seems to be telling that it's really an XML document, but yet you're treating it as text/plain with that regex .test(). I'm not sure about Safari, but it look like that it has overridden a toString() on the XML document object so that it returns the whole XML string so that your regex by coincidence works fine.
Without knowing the exact XML document it's hard to tell how exactly to fix it. If it's for example
<data>
<action>load</action>
</data>
Then you can check the presence of load value in the <action> tag using jQuery's own XML parsing facilities as follows:
function displayInfoReturn(data) {
if ($(data).find('action').text() == 'load') {
// ...
}
}
See also:
Easy XML consumption with jQuery
Related
I want to send by XMLHttpRequest a JSON object to a Perl Script (*.cgi)
But I can't decode the JSON object in the cgi file.
I always reveive the error message:
malformed JSON string, neither array, object, number, string or atom, at character offset 0 (before
"(end of string)")
This is my javascript code:
//ajax communication for receiver/transceiver
function doAjaxRequest(query)
{
if(whatReq == "")
{
alert('ERROR: Request-Type undefined');
return;
}
if (window.XMLHttpRequest)
{
arequest = new top.XMLHttpRequest(); // Mozilla, Safari, Opera
}
else if (window.ActiveXObject)
{
try
{
arequest = new ActiveXObject('Msxml2.XMLHTTP'); // IE 5
}
catch (e)
{
try
{
arequest = new ActiveXObject('Microsoft.XMLHTTP'); // IE 6
}
catch (e)
{
alert('ERROR: Request not possible');
return;
}
}
}
if (!arequest)
{
alert("Kann keine XMLHTTP-Instanz erzeugen");
return false;
}
else
{
var url = "****.cgi";
var dp = document.location.pathname;
arequest.open('post', url, true);
arequest.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
//receiver function
arequest.onreadystatechange = function()
{
switch (arequest.readyState)
{
case 4:
if (arequest.status != 200)
{
alert("Der Request wurde abgeschlossen, ist aber nicht OK\nFehler:"+arequest.status);
}
else
{
var content = arequest.responseText;
analyseResponse(content);
}
break;
default:
//alert("DEFAULT:" + arequest.readyState );
break;
}
}
//transceiver function
query="jsonObj=" + JSON.stringify({name:"John Rambo", time:"2pm"});
alert(query);
arequest.send(query)
}
}
And here the cgi file:
#!/usr/bin/perl
use CGI qw/:standard/;
use CGI::Carp qw(fatalsToBrowser);
use strict;
use warnings;
use JSON;
use Data::Dumper;
my $jsonObj = param('jsonObj');
my $json = JSON->new->utf8;
my $input = $json->decode( $jsonObj );
print Dumper(\$input);
Can you help me? I don't know how to access the JSON object.
Thank you very much.
This message says you've got non-JSON string in $jsonObj. One particulary common case is empty string. Try printing out raw content of $jsonObj and make sure you set up everything correctly for CGI::param to work and also check with browser's built in tools that it actually sends data.
Also I highly suggest you throwing away 10 years old ActiveX shit. You're using JSON.stringify and all the browsers that support it also support native XMLHttpRequest.
I was about to vote to put your question on hold because of insufficient information to reproduce and diagnose the problem, but then I realized that your question does contain enough clues to figure out what's wrong — they're just really well hidden.
Clue #1: Your error message says (emphasis mine):
malformed JSON string, neither array, object, number, string or atom, at character offset 0 (before "(end of string)")
This implies that your $jsonObj variable has length 0, i.e. it is empty.
So, what's causing it to be empty? Well, the Perl code looks like perfectly standard CGI stuff, so the problem must be either in your JS code, or in something that your haven't showed us (such as your web server config). Since we can't debug what we can't see, let's focus on your JS code, where we find...
Clue #2: There's something wrong with this line:
arequest.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
Of course, you can set any content type you want for a POST request, but CGI.pm expects to receive the content in one of the standard formats for HTML form submissions, i.e. either application/x-www-form-urlencoded or multipart/form-data. When it receives something labeled as application/json instead, it doesn't know how to parse it, and so won't. Thus, the param() method in your Perl script will return nothing, since, as far as it's concerned, the client sent no parameters that it could understand.
There should have been a warning about this somewhere in your web server error logs, but you presumably didn't think to check those. (Hint: you really should!)
(You could've also used the warningsToBrowser option of CGI::Carp to get those warnings sent as HTML comments, but I guess you weren't aware of that option, either. Also, to make that work reliably, you'd really need to use CGI::Carp before the CGI module, so that it can catch any early errors.)
Anyway, the fix is simple: just replace application/json in your JS code with application/x-www-form-urlencoded, since that's what what you're actually trying to send to the server. You should also make sure that your JSON data actually is properly URL-encoded before embedding it in the request, by passing the output of JSON.stringify() through encodeURIComponent(), like this:
var data = {name:"John Rambo", time:"2pm"};
var query = "jsonObj=" + encodeURIComponent(JSON.stringify(data));
(I'll also second Oleg V. Volkov's suggestion to get rid of all the obsolete ActiveX stuff in your JS code. In fact, you could do even better by using a modern JS utility library like, say, jQuery, which provides convenient wrapper functions so that you don't even have to mess with XMLHttpRequest directly.)
For a utility that asks a user to enter xml (say, from a file on a local disk), one can use jQuery's parseXML to convert the string into an XML document. This will work fine with well formed XML, but will fail silently if the XML is malformed.
For example:
xmltest=' <dog><arf>33 </arf></dog>';
xmlDoc = $.parseXML( xmltest) ;
xml = $(xmlDoc );
achild=xml.children(0).children(0);
alert('Content of child 1= '+achild.html();
will correctly yield: Content of child 1= 33
However
xmltest=' <dog><arf>33 </arf1></dog>';
xmlDoc = $.parseXML( xmltest) ;
xml = $(xmlDoc );
...
will fail silently.
More precisely; messages are displayed in the console. For example, Firefox displays:
[21:08:47.731] mismatched tag. Expected: </arf>
[21:08:47.731] Error: Invalid XML:<dog><arf>33 </arf1></dog>
Ie and chrome report similar messages.
The question: is there any way that javascript, or jquery, can detect this failure and access these error messages? The goal being to tell the user what kind of problems his XML file may have.
Note that one reason I am playing with this is to workaround the inability of Chrome to read local xml files using $.get (yes yes yes I understand it is a security thing, but it is also a pain in the neck if you want to use XML files to store a lot of attribute information, and don't want to run chrome from a command line. And what about IE?).
Using try and catch helps a bit...:
xmltest=' <dog><arf>33 </arf1></dog>';
try {
xmlDoc = $.parseXML( xmltest) ;
}
catch(e) {
wow='';
for (m in e) wow=wow+' : '+m+'='+e[m];
alert(e+':error== '+wow); return 1;
}
Yields in Firefox:
Error: Invalid XML: <dog><arf>33 </arf1></dog> :error== : fileName=file:///D:/docs/carCosts/jquery-1.10.2.js : lineNumber=516 : columnNumber=2
I have the following HTML and subsequent jQuery which appends the related HTML elements after the JSON request has been retrieved.
This implementation works in Google Chrome + Android browser + Safari, but is not populating the data in Firefox or Internet Explorer 9.
** Works in Chrome, Android browser, Firefox 4 ... does not work in Firefox 3.x and IE.
Static HTML:
<header class=line>
<div class="unit size3of4">
<h2 class="fullname"></h2>
<h4 class="nickname"></h4>
</div>
</header>
The jQuery code:
<script>
function load_user_info() {
var content_url = 'rest.api.url.com';
$.getJSON(content_url, {id:'11xx1122xx11'}, function(data){
console.log(data);
$.each(data, function(key, value) {
if (key == "fullname") {$('.fullname').append(value);}
else if (key == "nickname") {$('.nickname').append(value);}
});
});
}
load_user_info();
</script>
Slightly confused about the behavior between browsers. I can guarantee the JSON request is returning two variables: fullname & nickname and have confirmed this
In Firefox using the FireBug plugin I see the results of console.log(data).
In Chrome I see the results of the console.log(data) and the successful display of the fullname & nickname in the HTML after the JSON request.
Using jQuery 1.6.1 if it helps ...
JSON Output:
{"fullname":"johnny fartburger", "nickname":"jf"}
I'm slightly perplexed by what you're doing. I think the following code:
$.each(data, function (key, value) {
if (key == "fullname") {
$('.fullname').append(value);
} else if (key == "nickname") {
$('.nickname').append(value);
}
});
could be more easily represented by this:
$('.fullname').append(data.fullname);
$('.nickname').append(data.nickname);
I don't know if this will solve your problem, but it would certainly be an improvement.
The resulting problem was from the actual JSON data not being retrieved in IE. Hours and hours of search turned up the problem was that XDomainRequest is not natively supported by jQuery, specifically in a $.getJSON request
http://bugs.jquery.com/ticket/8283
In the end, I wrote a try {} catch {} statement that checks to see if $.browser.msie and if it is, do not use $.getJSON to retrieve the results, rather:
if ($.browser.msie) {
var xdr = new XDomainRequest();
xdr.open('GET', url);
xdr.onload = function() {
var data = $.parseJSON(this.responseText);
show_data(data);
}
xdr.send();
} else {
$.getJSON(url, function(data){
show_data(data);
});
}
So ... conclusion append does work in IE (7/8/9) and Firefox (3/4) but not when the AJAX results aren't being returned. Thanks everyone for your help and insight.
.append(value) is not very safe (for example if value="div").
You should use .html(value)
And what does data contain? I think .append is used to append elements. If data is plain text, that might not work (haven't tried it actually). Chrome uses a different engine and may convert the text to a textnode in the DOM.
Use .text() or .html() to set the contents of an element.
as an alternative with appendTo, try to use .text() too
.append() takes a HTML string as a parameter to append to the existing content. You probably want to replace the element's text, use .text() or .html() instead, depending on the contents of the value variable.
I'm doing a web where I heavily use AJAX requests to
a XML service. In fact, my web is a front-end with almost
no server whatsoever and uses AJAX to communicate with
the back-end.
Everything was going fine (I developed and tested in Ubuntu 9.04
and Firefox 3.0 as a browser).
One day I decided to see how my web did in IE8...
horror!
Nothing was working as it marvelously did in Firefox.
To be more specific, the Request.HTML's were not working.
As I said, my web relied heavily on that, so nothing worked.
I spent a day trying to get something running but I had no luck..
The only conclusion to which I arrived was that the XML was
incorrectly parsed
(I hope I'm in mistake). Let's get to the code:
var req = new Request.HTML({
url: 'service/Catalog.groovy',
onSuccess: function(responseTree, responseElements) {
var catz = responseElements.filter('category');
catz.each(function(cat){
// cat = $(cat);
var cat_id = cat.get('id');
var subcategory = cat.getElement('subcategory');
alert(cat_id);
alert(cat.get('html'));
alert(subcategory.get('html'));
}
},
onFailure: function(){...}
});
for example, that piece of code.
In firefox, it worked perfectly. It alerted an ID (for example, 7),
then it showed the contents of the category element, for example:
<subcategory id='1'>
<category_id>7</category_id>
<code>ACTIO</code>
<name>Action</name>
</subcategory>
and then it showed the contents of some inner element, in this case:
<category_id>7</category_id>
<code>ACTIO</code>
<name>Action</name>
In IE8, the first alert worked OK (alerted 7)
but the next alert (alert(cat.get('html'));) gave an empty string
and the last threw an Exception... it said something about subcategory
beeing null.
What I concluded with this all is that the elements where parsed
correctly
in Firefox, but in IE8 I only got the tags and the attributes OK,
everything else
was completely wrong (in fact, missing). I mean, the inner content of
all the
elements of the response where gone!
Other fact you could use: this code:
alert(cat.get('tag')); resulted in
Firefox: category
IE8: /category <-----------(?)
hmm what else...
oh yeah... the line you see commented above (cat = $(cat);) was
something
I tried to do to fix this. I read in the mootools Docs that IE needed
to explicitly call
the $ function on elements to get all the Element-magic ... but this
didn't fix anything.
I was so desperate... I even fiddled around with mootools.js code
OK, so...
What I want you, dear mootool-pro's is to help me solve this problem,
for I REALLY need the web to function in IE8, and in fact I chose
mootools to forget about compatibility problems...
ps: if something is not clear, please ASK! I'd appreciate any help :D
I had a similar issue like this sometime ago using jQuery. The problem was that, in IE, the incoming response data needed to be handled by the Microsoft.XMLDOM ActiveX object.
The general steps are to:
Instantiate the ActiveX object.
var oXmlDoc = new ActiveXObject("Microsoft.XMLDOM");
Pass it the incoming response data and load it.
oXmlDoc.loadXML(sXmlResponseData);
Parse it as needed.
You can check out the full resolution here.
I'm getting a syntax error (undefined line 1 test.js) in Firefox 3 when I run this code. The alert works properly (it displays 'work') but I have no idea why I am receiving the syntax error.
jQuery code:
$.getJSON("json/test.js", function(data) {
alert(data[0].test);
});
test.js:
[{"test": "work"}]
Any ideas? I'm working on this for a larger .js file but I've narrowed it down to this code. What's crazy is if I replace the local file with a remote path there is no syntax error (here's an example):
http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?
I found a solution to kick that error
$.ajaxSetup({'beforeSend': function(xhr){
if (xhr.overrideMimeType)
xhr.overrideMimeType("text/plain");
}
});
Now the explanation:
In firefox 3 (and I asume only firefox THREE) every file that has the mime-type of "text/xml" is parsed and syntax-checked. If you start your JSON with an "[" it will raise an Syntax Error, if it starts with "{" it's an "Malformed Error" (my translation for "nicht wohlgeformt").
If I access my json-file from an local script - no server is included in this progress - I have to override the mime-type... Maybe you set your MIME-Type for that very file wrong...
How ever, adding this little piece of code will save you from an error-message
Edit: In jquery 1.5.1 or higher, you can use the mimeType option to achieve the same effect. To set it as a default for all requests, use
$.ajaxSetup({ mimeType: "text/plain" });
You can also use it with $.ajax directly, i.e., your calls translates to
$.ajax({
url: "json/test.js",
dataType: "json",
mimeType: "textPlain",
success: function(data){
alert(data[0].test);
} });
getJSON may be insisting on at least one name:value pair.
A straight array ["item0","item1","Item2"] is valid JSON, but there's nothing to reference it with in the callback function for getJSON.
In this little array of Zip codes:
{"result":[["43001","ALEXANDRIA"],["43002","AMLIN"],["43003","ASHLEY"],["43004","BLACKLICK"],["43005","BLADENSBURG"],["43006","BRINKHAVEN"]]}
... I was stuck until I added the {"result": tag. Afterward I could reference it:
<script>
$.getJSON("temp_test_json.php","",
function(data) {
$.each(data.result, function(i, item) {
alert(item[0]+ " " + i);
if (i > 4 ) return false;
});
});
</script>
... I also found it was just easier to use $.each().
This may sound really really dumb, but change the file extension for test.js from .js to .txt. I had the same thing happen with perfectly valid JSON data files with pretty well any extension except .txt (example: .json, .i18n). Since I've changed the extension, I get the data and use it just fine.
Like I said, it may sound dumb but it worked for me.
HI
I have this same error when testing the web page on my local PC, but once it is up on the hosting server the error no longer happens. Sorry - I have no idea of the reason, but thought it may help someone else track down the reason
Try renaming "test.js" to "test.json", which is what Wikipedia says is the official extension for JSON files. Maybe it's being processed as Javascript at some point.
Have you tried disabling all the Firefox extensions?
I usually get some errors in the Firebug console that are caused by the extensions, not by the webs being visited.
Check if there's ; at the end of the test.js. jQuery executes eval("(" + data + ")") and semicolon would prevent Firefox from finding closing parenthesis. And there might be some other unseen characters that prevents it from doing so.
I can tell you why this remote location working though, it's because it's executed in completely different manner. Since it has jsoncallback=? as the part of query parameters, jQuery thinks of it as of JSONP and actually inserts it into the DOM inside <script> tags. Try use "json/test.js?callback=?" as target, it might help too.
What kind of webserver are you running that on? I once had an issue reading a JSON file on IIS because it wasn't defined as a valid MIME type.
Try configuring the content type of the .js file. Firefox expects it to be text/plain, apparently. You can do that as Peter Hoffmann does above, or you can set the content type header server side.
This might mean a server-side configuration change (like apache's mime.types file), or if the json is served from a script, setting the content-type header in the script.
Or at least that seems to have made the error go away for me.
I had a similar problem but was looping through a for loop. I think the problem might be that the index is out of bound.
Kien
For the people who don't use jQuery, you need to call the overrideMimeType method before sending the request:
var r = new XMLHttpRequest();
r.open("GET", filepath, true);
r.overrideMimeType("text/plain");