Chapter 13. Strings and JSON

 

Few can touch the magic String, and noisy Fame is proud to win them...

 
 --Oliver Wendell Holmes, 1809–1894

Text Strings

The manipulation of strings is one of the most common processes performed by most computer applications. By some estimates, over 30% of the typical program is devoted to working with strings. Hopefully whatever language you might choose to write your programs in will provide many varied and robust string manipulation functions and methods. In this aspect, JavaScript will not disappoint you. JavaScript provides over 20 methods associated with the string object. However, even this seemingly abundant functionality will usually turn out to be not quite enough.

Remember, a good API will allow a programmer to express his programming goals in as small a coding idiom as possible, usually a single function call. For example, your goal may be to make sure that a string is of a certain fixed length. Using JavaScript alone, you could achieve this goal in a small number of lines of code. However, there is no single function in JavaScript that will let you do this in a single statement. It turns out that this would be a pretty useful function to have. So Dojo provides it for us with the dojo.string.pad function. Dojo also provides another string function, dojo.string.substitute, which will allow you to change a string by substituting some part of the string for another.

We could imagine lots of additional Dojo functions that could help us achieve string manipulation goals in a single statement, but the team that developed Dojo also had some other objectives in mind. They wanted to keep Dojo as small as possible so that it would load faster and be easy to learn. Dojo has to support objectives that are, at times, at cross purposes with each other. It should be big enough to be useful (because of its breadth) and yet should also be small enough to be useful (because of its small footprint). In the category of string manipulation, Dojo supports both objectives by depending on the existing string primitives supported by native JavaScript to be sufficient for most cases. And for those additional special cases, Dojo provides a few string primitives, the already mentioned pad and substitute. Let’s now dive more deeply into these Dojo string functions.

The Dojo string functions are part of “core” not “base.” What this means is that they are not automatically available when you include the Dojo on your page. They must be imported using the dojo.require function. This is easy to do by just adding the following code to your page:

dojo.require("dojo.string")

Dojo Function: dojo.string.pad

This function is used to add leading or trailing characters to a string and to ensure that the string is at least a minimum length. Although it certainly would be possible to achieve this goal using the existing JavaScript String functions, the dojo.string.pad function allows us to do it in a single step, resulting in much more readable code. One of the typical uses for this function is to provide leading zeros on numbers when supporting the display of currency, dates, and other specialized number formats.

Following is the API for the dojo.string.pad function:

Table 13.1. Description of dojo.string.pad Function

Method Signature:

dojo.string.pad(string, size, char, end)

Summary:

Ensure that a string is of at least a specified size by putting characters at either the beginning or end of the string.

Parameter: string

String to be padded.

The string will not be modified. Instead, a new string will be returned.

Parameter: size

Length of the string to be padded.

If the length of the string is already greater than or equal to “size,” the return string is the same as the original string.

Parameter: char

Character used to pad the string.

Optional. If “char” is more than one character in length, it will still be padded onto the string that would result in a new string with a length greater than “size.”

Default is 0.

Parameter: end

Flag to put padding at beginning or end of string.

Optional. If end is true, padding will be applied to the end of the string; otherwise, the string will be padded at the beginning.

The default value is false.

This function does not change the string that it is evaluating. Instead, it returns a new string. Remember, in JavaScript, strings are “immutable.” That means they can’t be changed, rather a new string must be returned. The Dojo string functions take a string as a parameter, but they leave that string unchanged. The function returns a new string instance. This is also the way that the standard JavaScript string functions operate so Dojo strives to be consistent.

Usage Example for dojo.string.pad

Because the string functions are not included in dojo.js, it is necessary to import them using the dojo.require function.

        dojo.require("dojo.string");
        fractional = 27;
        pad = 4;
        valueParts = dojo.string.pad(fractional, pad, '0', false);

This code takes a string fractional and pads it to a length pad with leading zeros. Remember, the final parameter false causes the padding to be put at the beginning of fractional. The string fractional is not modified. The variable valueParts will now have a value of 0027;. Notice the integer “27” is being automatically converted to a string.

Dojo Function: dojo.string.substitute

As Murphy said, “If anything can go wrong, it will,” and that is certainly as true in computer applications as in many other of life’s endeavors. A common feature of our code will be to search for things that go wrong and notify the user with error messages. Error messages can be both general and specific. For example, if some user input is required but missing, the user may get a general error message such as “Field missing.” However, it is usually more helpful to get a specific error message like “Last name is missing.” The drawback to having very specific error messages is that the number of them can multiply very quickly, which can be an especially serious problem in JavaScript when we are trying to minimize the size of the page sent to the browser. Storing lots of possible error messages in the HTML file could cause its size to grow quickly.

Specific error messages often have a common form. Imagine some possible error messages that might occur in a typical Customer entry form:

Last name required.
        First name required.
        City required.

All these can be replaced with an error message in the more general form:

        ${0} required.

Where ${0} is a token that can be replaced with the specific field name when appropriate. This allows the page to display specific error messages that can be very helpful to the user, while at the same time minimizing the amount of space taken up by JavaScript code. The 0 in the token represents the first parameter that can be substituted into the message. Additional tokens could be used to allow more parameters to be substituted into the message.

        File '${0}' is not found in directory '${1}'.

In this case, ${0} would be replaced with a file name, and ${1} would be replaced with the name of a directory.

        File 'George.jpg' is not found in directory 'c:Pictures'.

Dojo provides a simple string function to make these kinds of parameter replacements easy. That function is dojo.string.substitute. It not only allows a string to have parameters injected into it, but it can perform processing on those parameters before the injection to provide extra formatting. Dojo also makes the token easier to read by using meaningful strings instead of just numbers as in the following example:

        ${fieldName} required.

The new token identifier fieldName is more meaningful then 0.

Following is the API description for the “substitute” function:

Table 13.2. Description of dojo.string.substitute Function

Method Signature:

dojo.string.substitute(template, map, transform, thisObject)

Summary:

Performs parameterized substitutions on a string.

Parameter: template

String containing tokens to be replaced.

Parameter tokens will be represented in template by text in the form of the form ${key} or ${key:format}. The later form specifies the name of a formatting function, which can be applied to the parameter. The name of the formatting function should correspond to the name in the token.

Parameter: map

Object or Array containing values to be substituted into template. The properties in the object should have names corresponding to the token values.

Parameter: transform

Function used to process the values before they are substituted into template. The transform function will be run after any formatting functions.

Parameter: thisObject

Object containing the formatting functions to be used for tokens that are in the form ${key:format}.

Optional. If this parameter is not used, the global namespace will be used for the location of the formatting functions.

A little more needs to be said about formatting functions. These are custom functions created to perform various kinds of formatting before the value is substituted into the template string. The types of formatting functions are completely up to you. You write them and give them whatever name you wish. Just be sure that the name you give the function corresponds to the value in the token. For example, ${lastName:upperCase} would run the upperCase function on the lastName parameter to be substituted into the template. Formatting functions should take a single unformatted value and return a formatted value.

Usage Example for dojo.string.substitute

We’ll start with a simple example first. Our template string will provide an error message for fields that require a dollar amount of at least a certain value.

        ${fieldName} must be less than ${dollarAmount}

Imagine that a field called “Credit Limit” must have a value less than $1000.00. Following is a code example for using the substitute function to inject the right values into this string to get an appropriate error message.

        template = "${fieldName} must be less than ${dollarAmount}"

        map = new Object();

        map.fieldName = "Credit Limit";
        map.dollarAmount = "$1000.00";

        errorMessage = dojo.string.substitute(template, map);

Notice the correspondence between the key name in the template and the name of the property in the map object (i.e. ${fieldName} and map.fieldName). The variable errorMessage will now have a value of "Credit Limit must be greater than $100";

The dojo.string.substitute function is fairly complicated, so to fully explain it, we’ll work with a more complex example. Imagine that we have a template string containing two parameters to be replaced. The first parameter will be a field name, and the second parameter will be a dollar amount, just as before. Now we also want to apply a function (which we will call ucFirst) to the first parameter to make sure the first letter is capitalized. We also want to apply a function (which we will call showMoney) to the second parameter to make sure it is in the form of a dollar amount with two trailing decimal digits. Additionally, we want to apply a function (which we will call trim) to remove any leading or trailing spaces in either of the parameters to be injected into our template.

Following is the template string for the messages:

        ${fieldName:ucFirst} must be greater than ${dollarAmount:showMoney}

We’ll have to define a few functions and then make the correct call to dojo.string.substititue. Let’s see what the code will look like. We’ll focus on the code related to the Dojo function call and leave out some of the detail code for the formatting functions.

        dojo.require("dojo.string");

        // Define functions

        ucFirst = function(value) {
           // This function will take a string and make sure the first letter
           // of the string is upper case and the subsequent letters
           // in the string are lower case.
           var newValue = ... // this is left as an exercise for the reader
           return newValue;

        dollarAmount = function(value) {
           // This function will take a number and put a dollar sign in front
           // of it and ensure that two decimal digits are at the end
           var newValue = ... // this is left as an exercise for the reader
           return newValue;
        }

        stringTrim = function(value) {
           // This function will remove leading and trailing
           // spaces from a string
           var newValue = ... // this is left as an exercise for the reader
           return newValue;
        }

        template = "${fieldname:ucFirst} must be less than ${dollarAmount:dollarAmount}"

        map = new Object();

        map.fieldName = " Credit Limit ";
        map.dollarAmount = 1000.00;

        errorMessage = dojo.string.substitute(template, map, stringTrim);

The value for errorMessage is "Credit Limit must be less than $1000.00".

JSON

JavaScript allows us to manipulate strings of generic text, but it also provides for a special type of text string called JSON, which is an acronym for JavaScript Object Notation. Now wasn’t that helpful? No? We’ll let’s describe it another way. JSON is a technique for representing JavaScript objects as text strings. After we convert a JavaScript object to text, we can transfer that text around the Internet using HTTP, which only allows plain text to be transmitted. In general, we’ll use JSON to transfer objects back and forth between the browser to the server. Another use for JSON is to create JavaScript objects using a more concise format than we get using methods calls. Let’s see an example. We’ll create two objects using both JavaScript and JSON.

First we’ll view the code for creating an object using JavaScript and the standard Object Oriented technique.

        // create a new object using JavaScript command

        object1 = new Object();
        object1.id = 100;
        object1.name = "ABC Customer";

Now let’s review the code for creating an equivalent object using JSON.

        // create a new object using JSON

        object2 = {id:100, name:"ABC Customer"};

Both objects are equivalent. They both have the same properties. After the object is created, there is really no way to tell they were created using different methods. Because we have two different but seemingly equivalent techniques, which one should you use? If you want to “be like Mike” and adhere to the conventions used by Dojo, you should use the JSON technique. Not only is JSON preferred by Dojo users, but it is also the preferred technique for most JavaScript programmers.

We can choose to use JSON or not when creating objects in JavaScript. But what options do we have when we want to send those objects to the server or get objects back from the server? When the browser builds an HTTP request to send to the server, data can either be sent in the URL (using the GET message type) or within the body of the request (using the POST message type). However, in either case, the data is sent as plain text. So we must find a way of converting a JavaScript object from the browser’s internal format into a plain text string that can be sent using HTTP.

JSON is the perfect solution for this problem. We can represent the object as a JSON text string and transmit it between the browser and the server. We’ve already seen that JavaScript provides a syntax for creating an object with JSON, but what about the corresponding syntax to take an object and convert it to JSON? As popular as JSON is within the JavaScript community, you would expect there would be an easy way to do that. But you would be wrong. JavaScript does not provide any native function for producing the JSON equivalent of an object. There is no toJSON method defined for JavaScript. So someone has to write one. Fortunately, for us, that “someone” is Douglas Crockford. He’s the source for all things JSON and a fount of general wisdom in his role as an industry guru. Dojo has taken advantage of his work by providing a few JSON functions based on his work.

Dojo Function: dojo.toJson

The Dojo function dojo.toJson will create a text string representing an object in the form of a JSON string. This process is called serializing the object, and the resulting string is the “serialization” of the object. Serialization is the computer science term for converting an object to a series of bytes that can be saved to a file or transmitted across some connection.

Following is the API for the dojo.toJson function:

Table 13.3. Description of dojo.toJson Function

Method Signature:

dojo.toJson(it, prettyPrint)

Summary:

This function will return a string containing the JSON representation of an object.

Parameter: it

Object to be serialized as JSON.

Parameter: prettyPrint

Flag to force the JSON text string to be formatted for easier viewing.

If prettyPrint is true, objects and arrays will be indented to make the output more readable. The variable dojo.toJsonIndentStr is used as the indent string. To use something other than the default (tab), change the variable before calling dojo.toJson().

Sometimes you would like to provide your own serialization method for turning an object into JSON. That is supported in Dojo by allowing you to add a function to your object (or its prototype) called either json or __json. It should take no parameters and return a string representing the JSON serialization of the object. There is no need to call the method directly; just use the dojo.toJson function, and it will check to see if you’ve provided your own custom method and will run it.

Usage Example for dojo.toJson

Let’s create an object and see what the JSON string looks like.

        // create a new object using JavaScript command

        object1 = new Object();
        object1.id = 100;
        object1.name = "ABC Customer";
        object1.toString = function() {
           return "Customer: " + this.name + ", (id: " + this.id + ")"; }

        jsonStr = dojo.toJson(object1);

The variable jsonString will now have a value of

        {
           "id": 100,
           "name": "ABC Customer",
           "phone": [
               "630-555-1212",
               "630-555-0000"
            ],
           "address": {
             "line1": "123 Main St",
             "city": "Chicago",
             "state": "IL",
             "zipCode": "60540"
           }
        }

Notice the special syntax for the "phone" array and the included object for "address".

Notice that even though the object contained a function, toString, it was not serialized. Functions are not serialized by this toJson, although it is perfectly acceptable to create your own custom json method, which would serialize the functions.

Another “gotcha” when using this function, is to try to serialize an object that has a reference to itself. You’ll end up causing toJson to fall into an infinite recursion that will eventually fail by running out of memory.

A final reminder, dojo.toJson is part of Dojo “base,” which means you don’t need a dojo.require statement to use it.

Dojo Function: dojo.fromJson

Ajax applications submit requests to the server for data. There are many available forms in which the data may be returned: plain text, name/value pairs, XML, and so on. One of the most desirable formats for many developers is to have the data returned as a JSON string, which can then be used to create JavaScript objects in the browser. As suggested before, you might think that turning a JSON string into JavaScript object would be a native feature of JavaScript. But you’d be wrong. There is a special technique we need to use to turn JSON into objects. We can’t just assign the string to a reference. It would be treated as a string. We need to actually execute the JSON string as JavaScript. Review the following example:

        jsonString = '{"id": 100, "name": "ABC Customer", "phone": ["630-555-1212", "630-555-0000"], "address": {"line1": "123 Main St", "city": "Chicago", "state": "IL", "zipCode": "60540"}}';

        var cust = eval( '(' + jsonString + ')'),

The variable "cust" now points to an object containing an "id", "name", "phone", and "address" property. Additionally, the "address" property references an object containing properties for "line1", "city", "state", and "zipCode".

Simply assigning the string to an object (jsonString) did not result in a creation of a new object. We have to use the native JavaScript eval function to actually execute the JSON string. The problem with this approach is that there is a possible security problem when we execute arbitrary JavaScript code. So you should first make sure that the string really is JSON and not some other JavaScript code returned by the server. The technique for doing that check is a bit involved, and fortunately, not necessary for us. Dojo has done this for us by providing a function to turn a JSON string into JavaScript objects and checking the code beforehand. The dojo.fromJson function performs this magic for us!

Following is the API for the dojo.fromJson function:

Table 13.4. Description of dojo.fromJson Function

Method Signature:

dojo.fromJson(json)

Summary:

This function takes a string in JSON format and builds new JavaScript objects from the string.

Parameter: json

JSON String

This string must be a properly formatted JSON string. The string will be evaluated to confirm that it is JSON and then will be executed as JavaScript to create new objects.

Note that if the JSON string contains a function definition, the function will be properly created in the new object.

Usage Example

        jsonString = '{"id": 100, "name": "ABC Customer", "phone": ["630-555-1212", "630-555-0000"], "address": {"line1": "123 Main St", "city": "Chicago", "state": "IL", "zipCode": "60540"}}';

        var cust = dojo.fromJson(jsonString);

The variable "cust" now points to an object containing an "id", "name", "phone", and "address" property. Additionally, the "address" property references an object containing properties for "line1", "city", "state", and "zipCode".

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.103.154