Web Programming Step by Step, 2nd Edition

Chapter 12: Ajax, XML, and JSON

Except where otherwise noted, the contents of this document are Copyright 2012 Marty Stepp, Jessica Miller, and Victoria Kirst. All rights reserved. Any redistribution, reproduction, transmission, or storage of part or all of the contents in any form is prohibited without the author's expressed written permission.

Valid XHTML 1.1 Valid CSS!

12.1: Ajax Concepts

Synchronous web communication

synchronous communication

Web applications and Ajax

Ajax bleach

Asynchronous web communication

synchronous communication

12.2: Using XMLHttpRequest

XMLHttpRequest (and why we won't use it)

A typical Ajax request

request
  1. user clicks, invoking an event handler
  2. handler's code creates an XMLHttpRequest object
  3. XMLHttpRequest object requests page from server
  4. server retrieves appropriate data, sends it back
  5. XMLHttpRequest fires an event when data arrives
    • this is often called a callback
    • you can attach a handler function to this event
  6. your callback event handler processes the data and displays it

Prototype's Ajax model

new Ajax.Request("url",
	{
		option : value,
		option : value,
		...
		option : value
	}
);

Prototype Ajax options

option description
method how to fetch the request from the server (default "post")
parameters query parameters to pass to the server, if any (as a string or object)
asynchronous should request be sent asynchronously in the background? (default true)
others: contentType, encoding, requestHeaders
new Ajax.Request("http://www.example.com/foo/bar.txt",
	{
		method: "get",
		parameters: {name: "Ed Smith", age: 29},   // "name=Ed+Smith&age=29"
		...
	}
);

Prototype Ajax event options

event description
onSuccess request completed successfully
onFailure request was unsuccessful
onException request has a syntax error, security error, etc.
others: onCreate, onComplete, on### (for HTTP error code ###)
new Ajax.Request("http://www.example.com/foo.php",
	{
		parameters: {password: "abcdef"},   // "password=abcdef"
		onSuccess: mySuccessFunction
	}
);

Basic Prototype Ajax template

	new Ajax.Request("url",
		{
			method: "get",
			onSuccess: functionName
		}
	);
	...

function functionName(ajax) {
	do something with ajax.responseText;
}

Ajax response object's properties

property description
status the request's HTTP error code (200 = OK, etc.)
statusText HTTP error code text
responseText the entire text of the fetched file, as a String
responseXML the entire contents of the fetched file, as a DOM tree (seen later)
function handleRequest(ajax) {
	alert(ajax.responseText);
}

XMLHttpRequest security restrictions

Ajax security error

Handling Ajax errors

	new Ajax.Request("url",
		{
			method: "get",
			onSuccess: functionName,
			onFailure: ajaxFailure,
			onException: ajaxFailure
		}
	);
	...
function ajaxFailure(ajax, exception) {
	alert("Error making Ajax request:" + 
	      "\n\nServer status:\n" + ajax.status + " " + ajax.statusText + 
	      "\n\nServer response text:\n" + ajax.responseText);
	if (exception) {
		throw exception;
	}
}

Debugging Ajax code

Firebug Ajax

Creating a POST request

new Ajax.Request("url",
	{
		method: "post",   // optional
		parameters: { name: value, name: value, ..., name: value },
		onSuccess: functionName,
		onFailure: functionName,
		onException: functionName
	}
);

Prototype's Ajax Updater

new Ajax.Updater("id", "url",
	{
		method: "get"
	}
);

PeriodicalUpdater

new Ajax.PeriodicalUpdater("id", "url",
	{
		frequency: seconds,
		name: value, ...
	}
);

Ajax.Responders

Ajax.Responders.register(
	{
		onEvent: functionName,
		onEvent: functionName,
		...
	}
);

12.3: XML

The bad way to store data

My note:
BEGIN
	TO: Tove
	FROM: Jani
	SUBJECT: Reminder
	MESSAGE (english):
		Hey there,
		Don't forget to call me this weekend!
END

What is XML?

Anatomy of an XML file

<?xml version="1.0" encoding="UTF-8"?>  <!-- XML prolog -->
<note>                                  <!-- root element -->
	<to>Tove</to>
	<from>Jani</from>                     <!-- element ("tag") -->
	<subject>Reminder</subject>           <!-- content of element -->
	<message language="english">          <!-- attribute and its value -->
		Don't forget me this weekend!
	</message>
</note>

Uses of XML

Pros and cons of XML

What tags are legal in XML?

Doctypes and Schemas

XML and Ajax

Ajax bleach

XML DOM tree structure

node tree
<?xml version="1.0" encoding="UTF-8"?>
<categories> 
  <category>children</category> 
  <category>computers</category> 
  ... 
</categories>

Recall: Javascript XML (XHTML) DOM

The DOM properties and methods* we already know can be used on XML nodes:

* (though not Prototype's, such as up, down, ancestors, childElements, or siblings)

Navigating the node tree

Using XML data in a web page

  1. use Ajax to fetch data
  2. use DOM methods to examine XML:
    • XMLnode.getElementsByTagName("tag")
  3. extract the data we need from the XML:
    • XMLelement.getAttribute("name"), XMLelement.firstChild.nodeValue, etc.
  4. create new HTML nodes and populate with extracted data:
    • document.createElement("tag"), HTMLelement.innerHTML
  5. inject newly-created HTML nodes into page
    • HTMLelement.appendChild(element)

Fetching XML using AJAX (template)

	new Ajax.Request("url",
		{
			method: "get",
			onSuccess: functionName
		}
	);
	...

function functionName(ajax) {
	do something with ajax.responseXML;
}

Analyzing a fetched XML file using DOM

<?xml version="1.0" encoding="UTF-8"?>
<employees>
	<lawyer money="5"/>
	<janitor name="Sue"><vacuumcleaner/></janitor>
	<janitor name="Bill">too poor</janitor>
</employees>

We can use DOM properties and methods on ajax.responseXML:

// zeroth element of array of length 1
var employeesTag = ajax.responseXML.getElementsByTagName("employees")[0];

// how much money does the lawyer make?
var lawyerTag = employeesTag.getElementsByTagName("lawyer")[0];
var salary = lawyerTag.getAttribute("money");   // "5"

// array of 2 janitors
var janitorTags = employeesTag.getElementsByTagName("janitor");
var excuse = janitorTags[1].firstChild.nodeValue;  // " too poor "

Analyzing a fetched XML file using DOM (2)

<?xml version="1.0" encoding="UTF-8"?>
<employees>
	<lawyer money="5"/>
	<janitor name="Bill"><vacuumcleaner/></janitor>
	<janitor name="Sue">too poor</janitor>
</employees>

What are the results of the following expressions?

// zeroth element of array of length 1
var employeesTag = ajax.responseXML.getElementsByTagName("employees")[0];

Larger XML file example

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
	<book category="cooking">
		<title lang="en">Everyday Italian</title>
		<author>Giada De Laurentiis</author>
		<year>2005</year><price>30.00</price>
	</book>
	<book category="computers">
		<title lang="en">XQuery Kick Start</title>
		<author>James McGovern</author>
		<year>2003</year><price>49.99</price>
	</book>
	<book category="children">
		<title lang="en">Harry Potter</title>
		<author>J K. Rowling</author>
		<year>2005</year><price>29.99</price>
	</book>
	<book category="computers">
		<title lang="en">Learning XML</title>
		<author>Erik T. Ray</author>
		<year>2003</year><price>39.95</price>
	</book>
</bookstore>

Navigating node tree example

// make a paragraph for each book about computers
var books = ajax.responseXML.getElementsByTagName("book");
for (var i = 0; i < books.length; i++) {
	var category = books[i].getAttribute("category");
	if (category == "computers") {
		// extract data from XML
		var title = books[i].getElementsByTagName("title")[0].firstChild.nodeValue;
		var author = books[i].getElementsByTagName("author")[0].firstChild.nodeValue;
		
		// make an XHTML <p> tag containing data from XML
		var p = document.createElement("p");
		p.innerHTML = title + ", by " + author;
		document.body.appendChild(p);
	}
}

Exercise: Late day distribution

A historical interlude: why XHTML?

Exercise: Animal game

The Animal Game

Practice problem: Animal game (cont'd)

Attacking the problem

Questions we should ask ourselves:

Debugging responseXML in Firebug

Firebug Debug Ajax

12.4: JSON

Pros and cons of XML

JavaScript Object Notation (JSON)

json
json

JavaScript Object Notation (JSON): Data format that represents data as a set of JavaScript objects

Recall: JavaScript object syntax

var person = {
	name: "Philip J. Fry",                           // string
	age: 23,                                         // number
	"weight": 172.5,                                 // number
	friends: ["Farnsworth", "Hermes", "Zoidberg"],   // array
	getBeloved: function() { return this.name + " loves Leela"; }
};
alert(person.age);                                 // 23
alert(person["weight"]);                           // 172.5
alert(person.friends[2]));                         // Zoidberg
alert(person.getBeloved());                        // Philip J. Fry loves Leela

An example of XML data

<?xml version="1.0" encoding="UTF-8"?>
<note private="true">
	<from>Alice Smith (alice@example.com)</from>
	<to>Robert Jones (roberto@example.com)</to>
	<to>Charles Dodd (cdodd@example.com)</to>
	<subject>Tomorrow's "Birthday Bash" event!</subject>
	<message language="english">
		Hey guys, don't forget to call me this weekend!
	</message>
</note>

The equivalant JSON data

{
	"private": "true",
	"from": "Alice Smith (alice@example.com)",
	"to": [
		"Robert Jones (roberto@example.com)",
		"Charles Dodd (cdodd@example.com)"
	],
	"subject": "Tomorrow's \"Birthday Bash\" event!",
	"message": {
		"language": "english",
		"text": "Hey guys, don't forget to call me this weekend!"
	}
}

Browser JSON methods

method description
JSON.parse(string) converts the given string of JSON data into an equivalent JavaScript object and returns it
JSON.stringify(object) converts the given object into a string of JSON data (the opposite of JSON.parse)

JSON expressions exercise

var data = JSON.parse(ajax.responseText);
{
	"window": {
		"title": "Sample Widget",
		"width": 500,
		"height": 500
	},
	"image": { 
		"src": "images/logo.png",
		"coords": [250, 150, 350, 400],
		"alignment": "center"
	},
	"messages": [
		{"text": "Save", "offset": [10, 30]}
		{"text": "Help", "offset": [ 0, 50]},
		{"text": "Quit", "offset": [30, 10]},
	],
	"debug": "true"
}

Given the JSON data at right, what expressions would produce:

var title = data.window.title;
var coord = data.image.coords[2];
var len = data.messages.length;
var y = data.messages[len - 1].offset[1];

JSON example: Books

Suppose we have a service books_json.php about library books.

JSON exercise

Write a page that processes this JSON book data.

Working with JSON book data

function showBooks(ajax) {
	// add all books from the JSON data to the page's bulleted list
	var data = JSON.parse(ajax.responseText);
	for (var i = 0; i < data.books.length; i++) {
		var li = document.createElement("li");
		li.innerHTML = data.books[i].title + ", by " +
				data.books[i].author + " (" + data.books[i].year + ")";
		$("books").appendChild(li);
	}
}

Bad style: the eval function

// var data = JSON.parse(ajax.responseText);
var data = eval(ajax.responseText);   // don't do this!
...