代码改变世界

bulletproof ajax: Data Formats

2012-08-29 15:46  youxin  阅读(289)  评论(0编辑  收藏  举报

Ajax is language agnostic, at least on the server. It doesn’t  matter what server-side language you use for your business  logic. However, when you are requesting data from the server, the data that’s sent from the server must be formatted in a way that the browser can understand. Your server-side programming
language of choice needs to return data in one of three ways: XML, JSON, or HTML. In this chapter, I’m going to examine each  data format so that you can make an informed decision as to  which one best suits your needs.

xml

 It’s important to note that XML doesn’t do anything. The language was created  as a means of storing data, not manipulating it.

一个实例:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
lang="en"> <head>
<meta http-equiv="content-type" content="text/html;
charset=utf-8" />
<title>People at Clearleft</title>
<style type="text/css">
@import url("clearleft.css");
</style>
<script type="text/javascript" src="fetchxml.js"></script>
</head>
<body>
<h1>People</h1>
<ul>
<li>
<a href="files/andy.xml"
onclick="grabFile(this.href); return false;">Andy</a>
</li>
<li>
<a href="files/richard.xml"
onclick="grabFile(this.href); return false;">Richard</a>
</li>
<li>
<a href="files/jeremy.xml"
onclick="grabFile(this.href); return false;">Jeremy</a>
</li>
</ul>
<div id="details"></div>
</body>
</html>

点击链接后,会提取xml的数据。

function grabFile(file)
{
     var request=getHTTPObject();
     if(request)
     {
         request.onreadystatechange = function() {
                parseResponse(request);
         };
         request.open("GET", file, true);
         request.send(null);
     }
}

关键是parseResponse函数。

function parseResponse(request) {
if (request.readyState == 4) {
if (request.status == 200 || request.status == 304) {
The XML is available through the responseXML property of the HTTPRequest object. I’m going to assign this property to the variable data:
   var data = request.responseXML;

The XML can be traversed using the same DOM methods that you would use
for traversing an HTML document. As long as you know the structure of the
XML being returned from the server, you can get at the information you want
using methods like getElementsByTagName and properties like nodeValue

Extracting data from XML

 jeremy.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<details>
    <name>Jeremy Keith</name>
   <website>http://adactio.com/</website>
   <email>jeremy@clearleft.com</email>
</details>

var name=data.getElementsByTagName("name")[0].firstChild.nodeValue;
var website = data.getElementsByTagName("website")[0].firstChild.nodeValue;
var email = data.getElementsByTagName("email")[0].firstChild.nodeValue

elements. Instead of outputting plain text, I  want to wrap these values inside HTML elements.

Generating content
Using DOM methods like createElement, createTextNode, and
appendChild, I can build up a chunk of HTML to contain the information
I have extracted. For instance, I want to output the values of name and
email like this:
<h2><a href="mailto:jeremy@clearleft.com">Jeremy Keith</a></
h2>

The h2 and a elements are created with the createElement method:
var header = document.createElement("h2");
var mailto = document.createElement("a");
I’m using the setAttribute method to give the a element the href value I
want:
mailto.setAttribute("href","mailto:"+email);
Last, I’m using the createTextNode method to create the text to go inside
the link:
var text = document.createTextNode(name);
Now I can use the appendChild method to join these nodes together:
mailto.appendChild(text);
header.appendChild(mailto);
I also want to output the website value like this:
   <a href="http://adactio.com/">http://adactio.com/</a>
This is accomplished using the same set of DOM methods:

var link = document.createElement("a");
link.setAttribute("href",website);
var linktext = document.createTextNode(website);
link.appendChild(linktext);
Now I have the HTML I want in the variables header and link. I need to put
those elements into the document.

 

<div id="details"></div> html本来就有。

I’m going to insert my newly created markup into the div with the ID details:
var details = document.getElementById("details");
First, I’ll ensure that this container element is empty:

while (details.hasChildNodes()) {
details.removeChild(details.lastChild);
}

The while loop will remove the last child until there are no more child
nodes left.
Now that the details element is empty, I can insert the markup I created

details.appendChild(header);
details.appendChild(link);
That’s it. The finished parseResponse function looks like this:

fetchxml.js:

 function getHTTPObject() {
    var xhr = false;
    if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        try {
                xhr = new ActiveXObject("Msxml2.XMLHTTP");
        }catch(e){
            try{
                xhr=new ActiveXObject("Microsoft.XMLHTTP");
            }catch(e){
                xhr=false;
            }
        }
    }
    return xhr;
}

function grabFile(file)
{
     var request=getHTTPObject();
     if(request)
     {
         request.onreadystatechange = function() {
                parseResponse(request);
         };
         request.open("GET", file, true);
         request.send(null);
     }
}

function parseResponse(request) {
        if (request.readyState == 4) {
        if (request.status == 200 || request.status == 304) {
            var data=request.responseXML;
            var name=data.getElementsByTagName("name")[0].firstChild.nodeValue;
            var website = data.getElementsByTagName("website")[0].firstChild.nodeValue;
               var email = data.getElementsByTagName("email")[0].firstChild.nodeValue;
             
           var header=document.createElement("h2");
           var   mailto = document.createElement("a");
           mailto.setAttribute("href","mailto:"+email);
           var text = document.createTextNode(name);
           mailto.appendChild(text);
            header.appendChild(mailto);
            
            var link = document.createElement("a");
            link.setAttribute("href",website);
            var linktext = document.createTextNode(website);
            link.appendChild(linktext);
            var details = document.getElementById("details");
            while (details.hasChildNodes()) {
            details.removeChild(details.lastChild);
            }
            
            details.appendChild(header);
            details.appendChild(link);
            }
        }
}

 

ADVANTAGES OF XML
XML is a very versatile data format. Instead of forcing your data into predefined
fields, you are free to invent a vocabulary to suit your data. This flexibility has
helped XML become hugely popular. It is one of the most common means of
transferring data within Web applications. That makes it very handy for Ajax
applications. If you ask a server-side programmer to return data in XML, your
request can be easily met.
The other nice thing about using XML is that you don’t need to learn a new
language to parse the data. Because the DOM was designed to parse any
kind of markup, you can recycle the knowledge that you have already gained
from DOM Scripting.

 

DISADVANTAGES OF XML
If you want to send XML from the server, you must ensure that it is sent with
the correct headers. If the content type isn’t “application/xml,” then the
responseXML property will be empty. If the XML is being generated on the fly
by a server-side programming language, it’s easy to miss this requirement.

While the DOM is eminently suited to parsing XML once it reaches the
browser, it can be a long-winded process.(冗长的处理过程) That’s evident in the contact details
example. It takes quite a few lines of JavaScript just to generate a small chunk
of markup.(花费许多js代码来产生一点markup标记) Each node has to be created and appended. For a complex applicationdealing with longer XML files, the code could quickly get out of hand.
One alternative to using the DOM is XSLT, or eXtensible Stylesheet Language
Transformations. This lets you transform XML into HTML by pointing it to a
template. Unfortunately, not all browsers support XSLT.

 

JSON
XML is designed to store data. In order to parse that data, you need some
other technology like the DOM or XSLT. Alternatively, you can use a data format
that stores data in a way that makes it easier for programming languages
to parse.
JSON, which stands for JavaScript Object Notation, is pronounced like the
name Jason. Incidentally, in Greek mythology, one of Jason’s Argonauts was
Telamon, father of Ajax.

 

JSON is the brainchild of Douglas Crockford, one of the preeminent JavaScript
coders in the world today (www.crockford.com).

Crockford proposes JSON as a lightweight alternative to XML. Anything that

can be stored in XML can also be stored in JSON. Both are text-based representations
of data, but while XML requires opening and closing tags, JSON
just uses colons, commas, and curly braces.
JSON isn’t a data format that needs to be interpreted by JavaScript: JSON is
JavaScript.(json不是一种数据格式,本身就是js)

AN EXAMPLE OF JSON
As you’ve already seen, there’s always more than one way of doing something
in JavaScript. Take this function declaration, for example:
function person() {
var name = "Richard Rutter";
var website = "http://clagnut.com/";
var email = "richard@clearleft.com";
}
This function isn’t very useful for achieving a task, but it is a handy way of
storing data in a single global variable. It could also be written like this:
var person = function() {
var name = "Richard Rutter";
var website = "http://clagnut.com/";
var email = "richard@clearleft.com";
};
In order to access all those local variables from outside the function, turn
person into an object:

var person = function() {
this.name = "Richard Rutter";
this.website = "http://clagnut.com/";
this.email = "richard@clearleft.com";
};

Now name, website, and email are available as properties of person:
person.name, person.website, and person.email.

That same object can be written like this:

{"person":{
"name":"Richard Rutter",
"website":"http://clagnut.com/",
"email":"richard@clearleft.com"
}
}

This is called an object literal. Values are assigned using colons instead of
equals signs. Each assignment is separated with a comma. The whole object
is encapsulated within curly braces. More sets of curly braces can be used to
nest more levels of information.
The values stored in an object literal can be strings, numbers, or Boolean
values. Object literals can also store functions, which are methods of the
object. But if you write an object literal purely for storing data, then you are
writing JSON.

使用json来存储我们刚才的数据。

Extracting data from JSON

 When my data was stored in XML, I was parsing the responseXML property.

JSON is simply a string of text. It is returned in the responseText property.
To access JSON data stored in the responseText property, I need to use
JavaScript’s eval statement. The eval function accepts a string as an argument.
This string is then executed as JavaScript code. Because a string of
JSON consists of JavaScript code, it can be evaluated.
Here, I’m evaluating the contents of the responseText property and assigning
the result to the variable data:
var data = eval('('+request.responseText+')');

Now I can access all of the JSON values as properties of data:
var name = data.person.name;
var email = data.person.email;
var website = data.person.website;

 

This dot syntax is shorter and more readable than the DOM methods I used
on the XML files:
var name = data.getElementsByTagName("name")[0].firstChild.nodeValue;

Once the data has been extracted, the parseResponse function continues
exactly as before, generating markup and inserting it into the document:

function parseResponse(request) {
if (request.readyState == 4) {
if (request.status == 200 || request.status == 304) {
var data = eval('('+request.responseText+')');
var name = data.person.name;
var email = data.person.email;
var website = data.person.website;
var header = document.createElement("h2");
var mailto = document.createElement("a");

后面的一样。

As you can see, there isn’t much difference between JSON and XML when
you’re using XMLHttpRequest to send data from your server.
If we take XMLHttpRequest out of the equation, JSON has one huge advantage
as a data format: you can request JSON data from a remote server。

THE SCRIPT TAG HACK
Security restrictions prevent us from using XMLHttpRequest to access any
domain other than the one serving up the JavaScript file being executed. This
means we can’t access remote servers like this:
request.open("GET", "http://api.search.yahoo.com/", true);
We can’t use XMLHttpRequest to access the Web APIs offered by so many
sites these days. That’s a real shame because most APIs return their data in
XML, which would then be available in responseXML.
The script element has no such security restrictions. It’s possible to access
a JavaScript file from another domain in this way:
<script type="text/javascript"
src="http://www.google-analytics.com/urchin.js"></script>

 

If you can request a JavaScript file from another domain, then you can also
request a JSON file. Remember, JSON is nothing more than (不过是)JavaScript.
Using some DOM Scripting, you can dynamically generate a script element.
This function accepts a URL as its argument. It creates a new script element
with the URL as its src attribute, and then adds the element to the head of
the document:

function getScript(url) {
var scripttag = document.createElement("script");
scripttag.setAttribute("type","text/javascript");
scripttag.setAttribute("src",url);
document.getElementsByTagName("head")[0].
appendChild(scripttag);
}

 

 

JSON and Web Services
Some APIs now offer JSON as an alternative to XML. All of Yahoo’s Web
Services can return JSON if it’s requested. If you’d like to try using the Yahoo
Search API, sign up for an application ID at http://api.search.yahoo.com/
webservices/register_application。

 

 

ADVANTAGES OF JSON
As a format for transmitting data, JSON is quite similar to XML, but it is a bit
more lightweight. Whereas every value in XML requires an opening and a
closing tag, JSON only requires a name to be written once.

Unlike XML, JSON doesn’t need to be sent from the server with a specific
content-type header. It can be sent as plain text.
JSON’s greatest asset is its ability to travel across domains. This means abandoning
the XMLHttpRequest object in favor of the script tag hack, but right
now, that’s the only way of directly retrieving data from another server.

 

DISADVANTAGES OF JSON
JSON’s syntax is very precise. One misplaced comma or missing curly brace
will put paid to an entire JSON object. You must also remember to escape
special characters such as quotation marks.

In order to extract the contents of a JSON object, it must be evaluated. The
eval function is powerful, and potentially dangerous. If you’re retrieving
JSON data from a third party that isn’t entirely trustworthy, it could contain
some malicious JavaScript code that will be executed with eval. For this
reason, Douglas Crockford has written a JSON parser that will parse only
properties, ignoring any methods (www.json.org/js.html).

 

HTML
If you are sending data as XML or JSON, you need to convert it into HTML
before displaying it in a Web browser. This extra step can be avoided if data is
sent as HTML to begin with.

<h2><a href="mailto:andy@clearleft.com">Andy Budd</a></h2>
<a href="http://andybudd.com/">http://andybudd.com/</a>

Technically, this isn’t an HTML file. There is no doctype declaration. There is
no body element, no head element, or even an html element. It would be
more accurate to call this a fragment or a snippet of HTML.
This fragment is ready to be inserted into the current document as it is.

Extracting Data from HTML
HTML consists of plain text. If the server sends HTML via XMLHttpRequest, it
will be available in the responseText property.

I don’t need to extract any data from responseText. It’s already preformatted
just the way I want it. All I need to do is dump it into the part of the page
that I want to update.
In this case, I want to update the div with the ID details:
var details = document.getElementById("details");
The simplest way of inserting a fragment of HTML is to update this element’s
innerHTML property.

function parseResponse(request) {
if (request.readyState == 4) {
if (request.status == 200 || request.status == 304) {
var details = document.getElementById("details");
  details.innerHTML = request.responseText;
}
}
}

 

 

In this chapter, you’ve seen three ways of formatting information returned
from the server in an Ajax response. Each format has its strengths and
weaknesses.
■ XML is a popular format that can be parsed using the DOM.
JSON can be used to retrieve data from a remote server, if you use the
script tag hack.
■ HTML fragments can be dumped straight into a page using innerHTML.
In my experience, using HTML fragments is often the quickest and easiest
way of updating part of a page without refreshing the whole page. Most of
the examples I’ll be showing you from now on will use this solution.