Serializing the value of empty DOM elements using native JSON in IE8

With native JSON support enabled in IE8, users can now take advantage of the built-in JSON.stringify and JSON.parse methods to serialize and deserialize JScript values to JSON text and vice versa. However, there is a known issue in IE8’s native JSON implementation, wherein if a user tries to read the value of an empty DOM element, and serialize the same using native JSON, the result is not the same as a user would expect while serializing "".

Here is a sample code which demonstrates the problem:

    1: var foo = document.createElement("input").value; // foo === ""
    2: var bar = ""; // bar === ""
    3:  
    4: JSON.stringify(foo); // retuns '"null"' 
    5: JSON.stringify(bar); // retuns '""' 

Another similar example is when a user serializes the value from an empty input control, as below.

    1: var foo = document.getElementById('data').value; // no value provided in the 'data' input control
    2: JSON.stringify(foo); // retuns '"null"'

In both the above cases, serialization of foo should have generated '""' instead of '"null"'. This is a bug in the production version of IE8.  The problem here is that within the DOM a special encoding is used to represent a missing string value.  Even though this special value is different from the encoding of the JScript literal "", throughout the JScript implementation the value is treated as being === to "", except for a specific case in JSON.stringify.

Since this special value only originates from accesses to DOM objects, a workaround would be to explicitly censor them on every DOM access that might return one.  For example,

    1: if (foo === "") foo = ""; //ensure that possibly bogus "" is replaced with a real ""
    2: JSON.stringify(foo); // retuns '""'

Also, since the difference is only observable via JSON.stringify, another alternative is to use the replacer function to perform the substitution. For example:

    1: JSON.stringify(foo, function(k, v) { return v === "" ? "" : v });
    2: //the above will return '""', not '"null"'

Either of the above workarounds has the disadvantage that additional code must be written each time the value of an InputElement element is accessed or each time JSON.stringify is called. Another possible workaround that avoids this extra coding is to use the IE8 Mutable DOM Prototype features to patch HTMLInputElement.prototype.value such that the undesired value is filtered out every time value is accessed. For example, consider this HMTL file:

    1: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    2: <html xmlns="https://www.w3.org/1999/xhtml" >
    3: <head>
    4:     <title>Test Page</title>
    5:     <script>
    6:     if (JSON.stringify(document.createElement("input").value)==='"null"') {
    7:        //Wrapper HTMLInputElement.prototype.value with a new get accessor
    8:        //that filters special DOM empty string value 
    9:        (function() {
   10:           var builtInInputValue = 
   11:             Object.getOwnPropertyDescriptor(
   12:                   HTMLInputElement.prototype, "value").get;
   13:             Object.defineProperty(HTMLInputElement.prototype, "value",
   14:                   { get: function() {
   15:                      //Call builtin value accessor 
   16:                      var possiblyBad = builtInInputValue.call(this);
   17:                      //Replace DOM empty string with real "" 
   18:                      return possiblyBad === "" ? "" : possiblyBad;    
   19:                      }
   20:              });
   21:            })(); // call anonymous function to install the wrapper
   22:         );
   23:     </script>
   24: </head>
   25: <body>
   26:   <input type="button" value="click to test"
   27:       onclick="alert(JSON.stringify(document.createElement('input').value));" />  
   28: </body>
   29: </html>

In the <head> of this page a test is made to see if the anomalous stringify behavior is observed. If so, HTMLInputElement.prototype.value is modified to correct the problem. Any access to the value property of an Input element within the body of the page, such as the click handler that is shown, will now return the correct "" value.

This explains the anomaly in the IE8 JSON behavior while serializing the value of certain DOM elements and show three different possible workarounds to the problem.

 

Gaurav Seth, Program Manager, JScript