By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,264 Members | 1,755 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,264 IT Pros & Developers. It's quick & easy.

How to escape the "&" in a JSON.stringfy() ajax call?

Claus Mygind
100+
P: 571
I am having trouble escaping the & in a JSON.stringfy() ajax call. I don't even know if I am stating the problem correctly here.

In my app I have linked json2.js from http://www.JSON.org/json2.js 2010-08-25(see attached file) to my app.

Then I have created an ajax call in the app to my server_side app in which I invoke the JSON.stringify(dataObj). My "dataObj" is an Associative Array. If one of the array element values contains the "&" the queryString variable is truncated. I was under the impression that JSON.stringify() would escape any control characters. but I am wrong.

What baffles me more is the fact I have even commented out the link to json2.js in my page header and the app does not crash when it get to the JSON.stringify() command.
Expand|Select|Wrap|Line Numbers
  1. <!-- <script type="text/javascript" language="JavaScript"    src="json2.js"></script>
  2.  -->
I don't know if it is because I am using FireFox 3.6.13. I thought that I had read that they have now included JSON right in FireFox.

The question remains "How do I escape the & or any other control character, when it occurs in a value"? I would hope this would be part of the json process.

Here is the offending name/value pair:
"TITLE":"Earthwork & Excavating Contracts Manager"

This is the string as transmitted
"TITLE":"Earthwork

Here is my ajax code.
Expand|Select|Wrap|Line Numbers
  1. //a public array used to store the ajax call response
  2. var    aCallBack = new Array();
  3.  
  4. function myAjax (callApp, dataObj, getOrSave) {
  5.  
  6.     this.makeCall = function (callApp, dataObj, getOrSave) {
  7.         var queryString  = "&appData="+JSON.stringify(dataObj);
  8.  
  9.                     //create ajax object
  10.         var request = window.ActiveXObject ?
  11.             new ActiveXObject('Microsoft.XMLHTTP') :
  12.             new XMLHttpRequest;
  13.  
  14.             //assemble data
  15.             var url = callApp+'?timeStamp=' + new Date().getTime();
  16.  
  17.             //actually make call and get response in chkStateChange function
  18.             request.open("POST", url, true);
  19.             request.onreadystatechange = function chkStateChange(){
  20.                                             if (request.readyState == 4) {
  21.                                                 if (request.status == 200) {
  22.                                                     processResponse(request.responseText);
  23.                                                 }
  24.                                             }
  25.                                          };
  26.             request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  27.             request.send( queryString );
  28.     };
  29.  
  30.     var processResponse = function (response) {
  31.  
  32.         aCallBack = response.split(';');
  33.  
  34.         if ( aCallBack[0] == "An error occured") { 
  35.             eAlert  = aCallBack[0]+"\n";
  36.             for (var i = 1; i < aCallBack.length; i++ )
  37.             {
  38.                 eAlert += aCallBack[i]+"\n";
  39.             }
  40.             alert( eAlert );
  41.         }else if (aCallBack[0] == "Record Saved")    {
  42.             alert("temp message Record Saved. /n look in _Navigation.js");        
  43.         }else{
  44.             updatePage();
  45.         }
  46.     };
  47. }
  48.  
  49. //ajax object created
  50. var ajax = new myAjax();
  51.  
Attached Files
File Type: zip json2.zip (5.4 KB, 166 views)
Jan 25 '11 #1

✓ answered by Claus Mygind

It turns out a better option is to simply encode the & when sending the JSON string to the server using POST.

The array I created is encoded by the:
var queryString = "appData="+JSON.stringify(dataObj);
(see code below)

the stringify function of JSON will encode all the special characters execpt the &. if the actual data contains an & the ajax call fails because the & will split the data at that point thinking it is a 2nd name/value pair.

What I can't understand is by comparison I am a novice at this why can I not find any reference on the net about how to handle the & in the data transmitted. The link I posted earlier uses a different format than JSON when transmitting data from the client to the server. So you are not taking advantage of JSON when the data arrives at the server. If there is more links that explain how to handle the &, I sure would like to read about it.

I made the following change to my code and got it to work

I build my array in the following manner:
Expand|Select|Wrap|Line Numbers
  1. /*
  2. -----------------------------------------
  3. I call this function to read all the data 
  4. nodes/elements on the form I want to save
  5. ------------------------------------------
  6. */
  7. function saveData(form)
  8. {
  9.     var dataObj = new Object();
  10.  
  11.     for (var i = 0; i < form.elements.length; i++)
  12.     {
  13.         var element = form.elements[i];
  14.         var type = element.type;
  15.         if (type == "checkbox")
  16.         {
  17.             if (element.checked)
  18.             {
  19.                 dataObj[element.id] ="T";
  20.             }else{
  21.                 dataObj[element.id] ="F";
  22.             }
  23.         }
  24.         else if (type == "radio")
  25.         {
  26.             if (element.checked)
  27.             {
  28.                 dataObj[element.id] = element.value;
  29.             }
  30.         }
  31.         else if (type == "hidden" || type == "password" || type == "text" ||
  32.                  type == "textarea")
  33.         {
  34. //text nodes which could contain the & are checked and encoded if necessary
  35.                 dataObj[element.id] = encode(element.value);
  36.         }
  37.         else if (type == "select-one" || type == "select-multiple")
  38.         {
  39.  
  40.             xText += form.element.selectedIndex.value;
  41.                 for (var j = 0; j < element.options.length; j++)
  42.                 {
  43.                     if (element.options[j].selected )
  44.                     {
  45. //text nodes which could contain the & are checked and encoded if necessary
  46. dataObj[element.id] = encode(element.options[j].value);
  47.                     }
  48.                 }
  49.         }
  50.     }
  51.  
  52. /*
  53. -------------------------------
  54. Here I make an ajax call to the 
  55. server via the function/method 
  56. I previously bound to the 
  57. variable ajax, see code below.
  58. -------------------------------
  59. */
  60.    ajax.makeCall("myServerSideApp.php", dataObj);
  61.  
  62. }
  63.  
  64. function encode(strVal)
  65. {
  66. /*
  67. -------------------------------------------
  68. using a regular expression I search 
  69. for the & and encode it with %26.  
  70.  
  71. This will automatically be decoded 
  72. in my php server side app when I call "json_decode($_REQUEST['appData'], true);",
  73. where appData is the JSON object 
  74. I transmitted.
  75. --------------------------------------------
  76. */
  77.     if (strVal.indexOf('&') > -1)
  78.     {
  79.         var searchStr = "&";
  80.         var replaceStr = "%26";
  81.         var re = new RegExp(searchStr, "g");
  82.         var result = strVal.replace(re, replaceStr);
  83.     }else{
  84.         var result = strVal;
  85.     }
  86.  
  87.     return result;
  88. }
  89.  
  90.  
  91. /*
  92. ----------------------------------------------
  93. Here is the actual ajax function called above
  94. -----------------------------------------------
  95. */
  96.  
  97. //a public array used to store the ajax call response
  98. var    aCallBack = new Array();
  99.  
  100. function myAjax (callApp, dataObj) {
  101.  
  102.     this.makeCall = function (callApp, dataObj) {
  103.         var queryString  = "appData="+JSON.stringify(dataObj);
  104.  
  105.         //create ajax object
  106.         var request = window.ActiveXObject ?
  107.             new ActiveXObject('Microsoft.XMLHTTP') :
  108.             new XMLHttpRequest;
  109.  
  110.             //create url
  111.             var url = callApp+'?timeStamp=' + new Date().getTime();
  112.  
  113.             //actually make call and get response in chkStateChange function
  114.             request.open("POST", url, true);
  115.             request.onreadystatechange = function chkStateChange(){
  116.                                             if (request.readyState == 4) {
  117.                                                 if (request.status == 200) {
  118.                                                     processResponse(request.responseText);
  119.                                                 }
  120.                                             }
  121.                                          };
  122.             request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  123.             request.send( queryString );
  124.     };
  125.  
  126.     var processResponse = function (response) {
  127.  
  128.         aCallBack = response.split(';');
  129.  
  130.         if ( aCallBack[0] == "An error occured") { 
  131.             eAlert  = aCallBack[0]+"\n";
  132.             for (var i = 1; i < aCallBack.length; i++ )
  133.             {
  134.                 eAlert += aCallBack[i]+"\n";
  135.             }
  136.             alert( eAlert );
  137.         }else if (aCallBack[0] == "Record Saved")    {
  138.             alert("message Record Saved.");        
  139.         }else{
  140.             updatePage();
  141.         }
  142.     };
  143. }
  144.  
  145. /*
  146. -----------------------------
  147. ajax object created and bound 
  148. to my myAjax function/method
  149. -----------------------------
  150. */
  151. var ajax = new myAjax();
  152.  
  153.  

Share this Question
Share on Google+
9 Replies


Oralloy
Expert 100+
P: 983
Claus,

Sorry for being quick, but I didn't take the time to completely analyze what you wrote. No insult intended, I'm searching for an answer and found your post.

Do you need to JSON escape the "&", or HTML escape it? Remember that there are a number of magic characters, that must be escaped in HTTP "GET" queries. Not just the "&" character, but the "+" and " " characters, as well. So what you probably need to do is to HTML encode your arguments. There are standard ways to do this, but I'm not an AJAX Guru, so I'll leave that to smarter folk than I.

Also, JSON is delivered as a standard part of recent browsers. You can test this out by building a trivial page like so:
Expand|Select|Wrap|Line Numbers
  1. <html>
  2.  <head>
  3.   <title>JSON Test</title>
  4.  </head>
  5.  <body>
  6.   JSON Test<br>
  7.   JSON.stringify = "<span id='myJSON' />"
  8.  </body>
  9. </html>
  10. <script type="text/javascript" language="JavaScript">
  11.   alert(JSON.stringify);
  12.   document.getElementById('myJSON').innerHTML = String(JSON.stringify);
  13. </script>
Cheers!
Oralloy
Jan 25 '11 #2

Claus Mygind
100+
P: 571
Thanks for the reply. Not sure what I was suppose to get from that. Cut and pasted the code in my FireFox 3.6.13 and got this result. Is this the intended and could you explain the outcome in a little more depth, so I have a better understanding?

This was the output I got:
JSON Test
JSON.stringify = "function stringify() { [native code] }
Jan 25 '11 #3

Oralloy
Expert 100+
P: 983
What that tells you is that JSON is already incorporated in your browser, so you don't have to include the json2 script library as part of your web page. Basically JSON is so useful, that it's part of the default scripting environment now days.

Also, as a test, try substituting '&ampl;' for '&' in your server response and see if that helps any. In general you should HTML encode all responses to queries, as '&' is not the only magic character you'll encounter.

Luck!
Oralloy
Jan 25 '11 #4

Claus Mygind
100+
P: 571
Thanks again for the quick explanation.

Just a couple of items here.

1) I am doing a POST not a GET
2) the array I am passing is being assembled on the client side not the server side.

& alone is the offending character. So I don't think I can substitute & with &ampl;

I also see now that & is not one of the offending characters to JSON. So that kind of leads back to your original thought about doing an HTML escape.

As explained here:
http://bytes.com/topic/javascript/an...haracters-json

I am pretty confident that my JSON.stingify() works because I tested it with the " double quote.

So I wonder if I will have to run the standard javaScript encode and decode when I create the array?

Also I would like to know if the code snippet I posted is correctly written? Meaning when it gets called, it indeed does stringify the array?
Jan 25 '11 #5

Oralloy
Expert 100+
P: 983
Claus,

Your basic problem is HTTP parameter parsing.

What happens is that the server recieves the parameter string queryString, which looks like "&appData="+JSON.stringify(dataObj).

Then the server parses the string based on HTTP's rules. To whit, '&' separates separates parameters, '=' separates parameter names from values, etc... Basically the rules are exactly the same as for a "GET" query; the only difference being that the parameters are sent in the body of the query, and not the URL part.

Nothing in HTTP's parameter specifications gives special meaning to quote (') characters in the parameter string. So, even though your '&' character is embedded in a well-formed JSON string, and is fully quoted, HTTP doesn't care. Similarly you will find that addition symbols, '+', are mapped to spaces.

The way to deal with this is to URL encode the parameter string by mapping special characters ('&', '+', ' ', '=', etc...) which occur in the parameter names and values into their appropriate transmission encodings.

Here are a couple links that might help:
Query_string#URL_encoding
Percent-encoding

Hopefully this helps some.

What surprises me is that the request object doesn't have a method which accepts "key/value" pair and encodes them automagically. That would save a lot of grief in the long run.

Oh well.

Good Luck! Let me know how it turns out.
Oralloy
Jan 25 '11 #6

Claus Mygind
100+
P: 571
Thank you for a very thorough reply. I get it now and I will just encode the data when I form the array.

Likewise I will decode the data on the server side.

I just did not know that when you do ajax POST that it would be different than a standard POST when you submit a form.
Jan 26 '11 #7

Claus Mygind
100+
P: 571
Well it is nice to know someone has already invented the wheel.

http://www.openjs.com/scripts/data/u..._encoded_data/

Looks like it should be a simple copy and paste operation for me.

Thanks again Oralloy for your outstanding help.
Jan 26 '11 #8

Oralloy
Expert 100+
P: 983
Claus,

I'm glad that you found a complete solution. It looks like the key to his code is the "encodeURIComponent" call at the bottom of his script. I didn't know about that method, so I'm glad you found it.

Cheers!
Jan 26 '11 #9

Claus Mygind
100+
P: 571
It turns out a better option is to simply encode the & when sending the JSON string to the server using POST.

The array I created is encoded by the:
var queryString = "appData="+JSON.stringify(dataObj);
(see code below)

the stringify function of JSON will encode all the special characters execpt the &. if the actual data contains an & the ajax call fails because the & will split the data at that point thinking it is a 2nd name/value pair.

What I can't understand is by comparison I am a novice at this why can I not find any reference on the net about how to handle the & in the data transmitted. The link I posted earlier uses a different format than JSON when transmitting data from the client to the server. So you are not taking advantage of JSON when the data arrives at the server. If there is more links that explain how to handle the &, I sure would like to read about it.

I made the following change to my code and got it to work

I build my array in the following manner:
Expand|Select|Wrap|Line Numbers
  1. /*
  2. -----------------------------------------
  3. I call this function to read all the data 
  4. nodes/elements on the form I want to save
  5. ------------------------------------------
  6. */
  7. function saveData(form)
  8. {
  9.     var dataObj = new Object();
  10.  
  11.     for (var i = 0; i < form.elements.length; i++)
  12.     {
  13.         var element = form.elements[i];
  14.         var type = element.type;
  15.         if (type == "checkbox")
  16.         {
  17.             if (element.checked)
  18.             {
  19.                 dataObj[element.id] ="T";
  20.             }else{
  21.                 dataObj[element.id] ="F";
  22.             }
  23.         }
  24.         else if (type == "radio")
  25.         {
  26.             if (element.checked)
  27.             {
  28.                 dataObj[element.id] = element.value;
  29.             }
  30.         }
  31.         else if (type == "hidden" || type == "password" || type == "text" ||
  32.                  type == "textarea")
  33.         {
  34. //text nodes which could contain the & are checked and encoded if necessary
  35.                 dataObj[element.id] = encode(element.value);
  36.         }
  37.         else if (type == "select-one" || type == "select-multiple")
  38.         {
  39.  
  40.             xText += form.element.selectedIndex.value;
  41.                 for (var j = 0; j < element.options.length; j++)
  42.                 {
  43.                     if (element.options[j].selected )
  44.                     {
  45. //text nodes which could contain the & are checked and encoded if necessary
  46. dataObj[element.id] = encode(element.options[j].value);
  47.                     }
  48.                 }
  49.         }
  50.     }
  51.  
  52. /*
  53. -------------------------------
  54. Here I make an ajax call to the 
  55. server via the function/method 
  56. I previously bound to the 
  57. variable ajax, see code below.
  58. -------------------------------
  59. */
  60.    ajax.makeCall("myServerSideApp.php", dataObj);
  61.  
  62. }
  63.  
  64. function encode(strVal)
  65. {
  66. /*
  67. -------------------------------------------
  68. using a regular expression I search 
  69. for the & and encode it with %26.  
  70.  
  71. This will automatically be decoded 
  72. in my php server side app when I call "json_decode($_REQUEST['appData'], true);",
  73. where appData is the JSON object 
  74. I transmitted.
  75. --------------------------------------------
  76. */
  77.     if (strVal.indexOf('&') > -1)
  78.     {
  79.         var searchStr = "&";
  80.         var replaceStr = "%26";
  81.         var re = new RegExp(searchStr, "g");
  82.         var result = strVal.replace(re, replaceStr);
  83.     }else{
  84.         var result = strVal;
  85.     }
  86.  
  87.     return result;
  88. }
  89.  
  90.  
  91. /*
  92. ----------------------------------------------
  93. Here is the actual ajax function called above
  94. -----------------------------------------------
  95. */
  96.  
  97. //a public array used to store the ajax call response
  98. var    aCallBack = new Array();
  99.  
  100. function myAjax (callApp, dataObj) {
  101.  
  102.     this.makeCall = function (callApp, dataObj) {
  103.         var queryString  = "appData="+JSON.stringify(dataObj);
  104.  
  105.         //create ajax object
  106.         var request = window.ActiveXObject ?
  107.             new ActiveXObject('Microsoft.XMLHTTP') :
  108.             new XMLHttpRequest;
  109.  
  110.             //create url
  111.             var url = callApp+'?timeStamp=' + new Date().getTime();
  112.  
  113.             //actually make call and get response in chkStateChange function
  114.             request.open("POST", url, true);
  115.             request.onreadystatechange = function chkStateChange(){
  116.                                             if (request.readyState == 4) {
  117.                                                 if (request.status == 200) {
  118.                                                     processResponse(request.responseText);
  119.                                                 }
  120.                                             }
  121.                                          };
  122.             request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  123.             request.send( queryString );
  124.     };
  125.  
  126.     var processResponse = function (response) {
  127.  
  128.         aCallBack = response.split(';');
  129.  
  130.         if ( aCallBack[0] == "An error occured") { 
  131.             eAlert  = aCallBack[0]+"\n";
  132.             for (var i = 1; i < aCallBack.length; i++ )
  133.             {
  134.                 eAlert += aCallBack[i]+"\n";
  135.             }
  136.             alert( eAlert );
  137.         }else if (aCallBack[0] == "Record Saved")    {
  138.             alert("message Record Saved.");        
  139.         }else{
  140.             updatePage();
  141.         }
  142.     };
  143. }
  144.  
  145. /*
  146. -----------------------------
  147. ajax object created and bound 
  148. to my myAjax function/method
  149. -----------------------------
  150. */
  151. var ajax = new myAjax();
  152.  
  153.  
Feb 4 '11 #10

Post your reply

Sign in to post your reply or Sign up for a free account.