﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-鹰翔宇空-文章分类-AJAX</title><link>http://www.blogjava.net/TrampEagle/category/9799.html</link><description>学习和生活
</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 10:31:58 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 10:31:58 GMT</pubDate><ttl>60</ttl><item><title>prototype1.3.1源代码解读</title><link>http://www.blogjava.net/TrampEagle/articles/30261.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Sat, 11 Feb 2006 06:06:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/30261.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/30261.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/30261.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/30261.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/30261.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 原文引自：http://www.javaeye.com/pages/viewpage.action?pageId=1131prototype1.3.1源代码解读作者：醒来编辑：robbinprototype.js/** * 定义一个全局对象, 属性 Version 在发布的时候会替换为当前版本号 */var Prototype = {  Version: '1.3.1',...&nbsp;&nbsp;<a href='http://www.blogjava.net/TrampEagle/articles/30261.html'>阅读全文</a><img src ="http://www.blogjava.net/TrampEagle/aggbug/30261.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-02-11 14:06 <a href="http://www.blogjava.net/TrampEagle/articles/30261.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>AJAX技术汇总</title><link>http://www.blogjava.net/TrampEagle/articles/27902.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Fri, 13 Jan 2006 04:50:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/27902.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/27902.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/27902.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/27902.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/27902.html</trackback:ping><description><![CDATA[引自：<a href="/zyb9114/articles/23357.html">http://www.blogjava.net/zyb9114/articles/23357.html</a><br /><br /><p>AJAX全称为“Asynchronous JavaScript and XML”（异步JavaScript和XML），是指一种创建交互式网页应用的网页开发技术。它有机地包含了以下几种技术： 
</p><p>Ajax（Asynchronous JavaScript + XML）的定义</p><p>基于web标准（standards-based presentation）XHTML+CSS的表示； <br /><br />使用 DOM（Document Object Model）进行动态显示及交互； <br /><br />使用 XML 和 XSLT 进行数据交换及相关操作； <br /><br />使用 XMLHttpRequest 进行异步数据查询、检索； <br /><br />使用 JavaScript 将所有的东西绑定在一起。<br /><br />类似于DHTML或LAMP，AJAX不是指一种单一的技术，而是有机地利用了一系列相关的技术。事实上，一些基于AJAX的“派生/合成”式（derivative/composite）的技术正在出现，如“AFLAX”。</p><p>AJAX的应用使用支持以上技术的web浏览器作为运行平台。这些浏览器目前包括：Mozilla、Firefox、Internet Explorer、Opera、Konqueror及Safari。但是Opera不支持XSL格式对象，也不支持XSLT。[1]</p><p><strong>与传统的web应用比较</strong></p><p>传统的web应用允许用户填写表单(form)，当提交表单时就向web服务器发送一个请求。服务器接收并处理传来的表单，然后返回一个新的网页。这个做法浪费了许多带宽，因为在前后两个页面中的大部分HTML代码往往是相同的。由于每次应用的交互都需要向服务器发送请求，应用的响应时间就依赖于服务器的响应时间。这导致了用户界面的响应比本地应用慢得多。</p><p>与此不同，AJAX应用可以仅向服务器发送并取回必需的数据，它使用SOAP或其它一些基于XML的web service接口，并在客户端采用JavaScript处理来自服务器的响应。因为在服务器和浏览器之间交换的数据大量减少，结果我们就能看到响应更快的应用。同时很多的处理工作可以在发出请求的客户端机器上完成，所以Web服务器的处理时间也减少了。<br /><br /><img height="455" hspace="5" src="http://www.51cto.com/files/uploadimg/20051123/0952450.png" width="475" align="baseline" /><br /><br />传统web应用与AJAX应用的比较：处理用户交互</p><p><img class="" height="598" hspace="5" src="http://www.51cto.com/files/uploadimg/20051123/0952451.png" width="475" align="baseline" /><br class="" />传统web应用与AJAX应用的比较：交互模式</p><p><span class="top11"><strong>微软的Ajax</strong></span></p><p></p><p>微软目前目前对于通过Ajax风格的编程在浏览器中实现日益流行的富客户端应用比较感兴趣。今后的IE中将拥有Ajax的所有东西——DHTML、JScript和XmlHttp。实际上Outlook Web Acces从1998年开始就已经提供了这种伟大的浏览体验了。在ASP.NET 2.0中，微软使用异步回调及舒适的Ajax风格的应用程序的编写更加简单，并且，微软为此提供了内建的控件。</p><p>最近，几乎所有的浏览器都提供了Ajax所需的技术，使用这种模式的富客户端应用程序也不断出现。今天，世界上出现了不计其数的Ajax风格的站点，包括Google的很多站点、A9和Flickr。微软的很多站点也使用了这项技术，如Start.com和MSN虚拟地球。</p><p>Ajax的风行说明用户对于丰富的Web体验的需求日益增长。然而，开发和调试Ajax风格的Web应用程序是一项非常艰难的工作。要编写一个丰富的Web UI，开发者需要详细地掌握DHTML和JavaScript，并且还要掌握各种浏览器之间在设计细节上的不同。然而没有那些工具能够简化这些应用程序的设计和开发。最后，调试和测试这些应用程序会变得异常困难。</p><p>微软致力于简化Ajax风格Web应用的开发，并提供丰富的、可交互的和个性化的用户体验。开发者可以对客户端脚本不甚了解；但他们可以很容易地开发和调试这种应用程序。</p><p>出于这一目的，微软启动了一个新的项目，研发代号“Atlas”。Atlas为开发这带来了如下特性：<br class="" />·Atlas客户端脚本框架<br class="" />·Atlas的ASP.NET服务器控件<br class="" />·ASP.NET Web Services集成<br class="" />·Atlas的ASP.NET构建块<br class="" />·客户端构建块服务</p><p>你可能会问的一个问题是，Atlas如何在Avalon和智能客户端上使用？</p><p>我们可以看到，Atlas是编写丰富的、可交互的和个性化的Web浏览器应用程序的最好方式。而Avalon是微软的下一代表现层模型，可以在Windows平台上提供最丰富的用户体验。Avalon将使用最新的媒体集成功能和硬件加速设备，提供卓越的视觉体验。Avalon将带来超越浏览器的体验。</p><p>当然，当你构建Avalon应用程序的时候，你依然可以重用ASP.NET和Atlas中的编程模型。例如，Avalon客户端上依然可以使用ASP.NET构建块服务和客户端构建块服务。这种模型可以使你平滑地过渡到下一代应用程序上。</p><p>微软提供了一个工具包，用来完成Ajax的功能，称作Atlas。从微软的Scott Guthrie的blog上看来，这个东西应该是ASP.NET 2.0里面的。Scott肯定地表示，“Atlas客户端脚本框架（Client Script Framework）可以运行在所有的现代浏览器上并且何以与任何Web服务器交互”，这说明他们正在以跨浏览器的态度来开发Ajax风格的远程脚本，这无疑是一个巨大的转变；过去的微软，把任何东西都搞成了特定于IE的，而一旦其开发工具能够真的提供彻底的跨浏览器支持，将能够笼络更多的ASP.ENT开发者，他们无需了解任何细节就可以创建跨浏览器代码。</p><p>Atlas客户端脚本框架是可扩展的，100%面向对象的JavaScript客户端脚本框架，允许开发这很容易地构建拥有丰富的UI工能并且可以连接Web Services的Ajax风格浏览器应用程序。使用Atlas，开发者可以使用DHTML、JavaScript和XMLHTTP来编写Web应用程序，而无须掌握这些技术的细节。</p><p>Atlas客户端脚本框架可以在所有的现代浏览器上运行，而不需要Web服务器。它还完全不需要安装，只要在页面中引用正确的脚本文件即可。</p><p>Atlas客户端脚本框架包含下列组件：<br class="" />·一个可扩展的和新框架，其中为JavaScript添加了很多新特性，如生存期管理、集成、多播事件处理器和接口<br class="" />·一个基础类库，提供了通用特性，如丰富的字符串操作功能、计时器和运行任务等<br class="" />·一个UI框架，可以跨浏览器实现动态行为<br class="" />·一个网络栈，用于简化对服务器的连接和对Web Services的访问<br class="" />微软为ASP.NET应用程序专门设计了一组Ajax风格的服务器控件，并且加强了现有的ASP.NET页面框架和控件，以便支持Atlas客户端脚本框架。<br class="" />ASP.NET 2.0中有一项称作异步客户端回调的新特性，使得构建无中断的页面变得很容易。异步客户端回调包装了XMLHTTP，能够在很多浏览器上工作。ASP.NET本身包括了很多使用回调的控件，包括具有客户端分页和排序功能的GridView和DetalsView控件，以及TreeView空间的虚拟列表支持。<br class="" />Atlas客户端脚本框架将完全支持ASP.NET 2.0回调，但微软希望进一步增强浏览器和服务器之间的集成性。例如，你可以将Atlas客户端控件的数据绑定指定为服务器上的ASP.NET数据源控件，并且可以从客户端异步地控制Web页面的个性化特征。</p><p>和任何客户端应用程序一样，一个Ajax风格的Web应用程序通常也需要访问Web服务器的一些功能。Atlas应用程序连接服务器的模型和其他平台类似，都是使用Web Services来实现。</p><p>通过ASP.NET Web Services集成，Atlas应用程序将可以在任何支持XMLHTTP的浏览器上通过Atlas客户端将本框架来直接访问任何宿主于ASP.NET的asmx或Indigo服务。该框架将会自动处理代理和脚本到对象、对象到脚本的序列化问题。通过使用Web Services集成，开发者可以使用单一的编程模型来编写Web Services，并且在任何应用程序中使用它们，不论是基于浏览器的站点上还是智能客户端应用程序中。</p><p>在ASP.NET 2.0中，微软构建了一组丰富的构建块服务（Building Block Services），这使得构建强大、个性化的Web应用程序变得不可思议的简单。这些构建块极大地降低了在开发通用的Web应用程序过程中需要编写的代码数量，比如管理用户、通过角色验证用户和存储用户的个性化设置信息等。</p><p>使用Atlas，我们可以在任何浏览器上的任何客户端应用程序中向访问Web Services那样访问这些功能。例如，如果你正在开发一个站点，来显示用户的TO-DO项目，你可以使用ASP.NET的Profile服务来将他们存放在服务器上的用户自定义配置文件中。这样即使用户从一台机器上转移到另一台机器上，也同样可以访问这些项目。</p><p>微软将提供的服务包括（全部是基于ASP.NET 2.0的）：<br class="" />- Profile：在服务器上存放每个用户特有的数据<br class="" />- UI个性化：在服务器上存放个性化的UI设置信息<br class="" />- 验证：验证用户<br class="" />- 角色：基于用户的角色验证用户任务和提供不同的UI<br class="" />由于这些构建块是服务器端的，开发者需要对他们应用和其他站点一样的安全模型。这些服务不需要客户端下在任何东西——只要在浏览器中引用脚本代理即可。所有的ASP.NET 2.0构建块服务都是可插拔的，这使用一种通用的提供者模型可扩展模式在后台实现。微软提供的内建提供程序允许开发这使用SQL Server数据库或Active Directory作为存储容器，开发者也可以很容易地插接自己的提供程序。例如，你可能希望使用集群而不是数据库服务器来存放用户的配置文件，这时你只需将你的提供程序插接近来即可。</p><p>除了DHTML、JScript和XMLHTTP，微软还提供了一组附加的服务来加强客户端的功能并提供增强的体验。对于这样的服务，本地浏览器缓存就是一个很好的例子。当启用了本地浏览器缓存时，Web站点就可以将内容存储到患从中，并在需要的时候很快地取出。但浏览器并未提供向缓存中存放数据的API，而且象Google Map或OWA这样的应用程序不得不通过很多工作产生一个唯一的URL才能使浏览器缓存它。在Atlas中，微软提供了可编程的本地存储/缓存，因此应用程序可以很方便、有效并且安全在本地缓存数据。</p><p>同其他应用程序的集成是检验Web体验是否丰富的另一个新的标准。例如，当一个用户浏览一个拍卖网站并对一件商品出价时，他可能想随时知道这个拍卖什么时候结束，但他如何才能将这个事件添加到他们个人的日历程序中？Atlas带来了一系列客户端构建块服务，当用于选择“添加到日历”时，浏览器将调用接驳点来获取日历数据，并将其传递到本地的日历程序中。此时页面上无须下载或运行任何特殊的代码或执行任何初始化动作，因此，这比ActiveX要安全得多。<br /><br /><span class="top11"><strong>基于Ajax的应用程序架构</strong></span></p><p></p><p>浏览器端框架被划分成两大类：</p><p>·应用程序框架：提供浏览器的功能，但是常以包括窗口小部件抽象和另外的部件而出名，其功能主要围绕桌面GUI框架。</p><p>·基本结构框架：提供基本的管道和可移植的浏览器抽象，让开发者去创建内容。典型的功能：</p><p>* 针对XMLHttpRequest的包装器以封装浏览器-服务器的交互。(所有的框架都提供这一功能)。</p><p>* XML操作和查询。</p><p>* 根据来自XMLHttpRequest的应答执行DOM操作。</p><p>* 在一些情况中，与另外的浏览器端技术如Flash(和潜在的Java applets)集成在一起。</p><p>而服务器端框架通常以下面两种方式工作(尽管它们在这里根据语言的不同进行了分类)：</p><p>·HTML/JS生成：服务器提供完整的HTML/Javascript代码生成和浏览器-服务器协调，结果是只有浏览器端编码可以被定制。</p><p>·远程调用：Javascript调用直接被路由到服务器端功能(例如Java方法)并返回到Javascript回叫处理器；或者Javascript调用服务器以提取信息，例如会话细节，数据库查询等。</p><p><strong>1 纯Javascript：应用程序框架</strong></p><p>1.1 Bindows(自从2003年)</p><p>网址是：<a href="http://www.bindows.net/"><font color="#1d58d1">http://www.bindows.net</font></a>，Bindows是一个软件开发包(SDK)，它，通过强力联合DHTML，JavaScript，CSS和XML等技术，能生成高度交互的互联网应用程序-成为现代的桌面应用程序的强有力对手。Bindows应用程序不要求下载和也不需要在用户端安装-仅要求有一个浏览器(也不需要Java，Flash或者ActiveX)。Bindows有可能领导面向对象开发的AJAX应用程序的平台。</p><p>·它是商业化的，使用来自于MB的技术(总部位于GA USA，主要开发中心在瑞典，成立于2002年)。</p><p>Bindows框架提供给你：</p><p>·基于类的面向对象的API</p><p>·一套完整的窗口系统，提供宽范围的窗口小部件支持，包括菜单、表单、格子、滑动条、量程，甚至更多</p><p>·用于开发zero-footprint SOA客户端应用程序的领先的工具箱</p><p>·本机的XML，SOAP和XML-RPC支持</p><p>·单用户到企业级的支持</p><p>·内建的对AJAX的支持</p><p>Bindows开发环境：</p><p>·支持企业级规模的工程开发</p><p>·跨浏览器，跨平台支持</p><p>·服务器独立结构</p><p>·与新的和现有资源的互操作性</p><p>·一致性开发方法学</p><p>1.2 BackBase(自从2003年)</p><p>网址是：<a href="http://www.backbase.com/"><font color="#1d58d1">http://www.backbase.com</font></a>，是一个全面的浏览器端框架，支持丰富的浏览器功能以及与.NET和Java的集成。</p><p>·商业化，来自于Backbase B.V(总部在Amsterdam，成立于2003年)。</p><p>1.3 DOJO(开发中;自从2004年9月)</p><p>网址是：<a href="http://dojotoolkit.org/"><font color="#1d58d1">http://dojotoolkit.org/</font></a>，提供全面窗口小组件和浏览器-服务器消息支持。</p><p>·为创建定制的Javascript窗口小组件提供框架支持。 </p><p>·预置的窗口小组件库。</p><p>·浏览器-服务器消息支持-XMLHttpRequest和另外的机制。</p><p>·支持浏览器中的URL操纵功能。</p><p>·开源许可(学术自由许可2.1(<a href="http://opensource.org/licenses/afl-2.1.php"><font color="#1d58d1">http://opensource.org/licenses/afl-2.1.php</font></a>))，由JotSpot(<a href="http://www.jot.com/"><font color="#1d58d1">http://www.jot.com/</font></a>)的Alex Russell(<a href="http://alex.dojotoolkit.org/"><font color="#1d58d1">http://alex.dojotoolkit.org/</font></a>)所领导。</p><p>1.4 Open Rico(开发中;自从2005年5月;基于早期的私有框架)</p><p>网址是：<a href="http://openrico.org/demos.page"><font color="#1d58d1">http://openrico.org/demos.page</font></a>，是一多用途框架，支持Ajax基础结构和用户交互。</p><p>·一个XMLHttpRequest应答能被路由到一个或者更多回叫操作，DOM对象，或者Javascript对象。</p><p>·容易鼠标拖动支持。</p><p>·Ajax动画，例如缩放和变换。</p><p>·"行为"-实质上是窗口小组件库。</p><p>·使用指南(<a href="http://www.mirimar.net/mailbrowser/"><font color="#1d58d1">http://www.mirimar.net/mailbrowser/</font></a>)，由RussMirimar的Yonah所提供</p><p>·开源。源于Sabre航空公司解决方案，由Bill Scott(<a href="http://looksgoodworkswell.blogspot.com/"><font color="#1d58d1">http://looksgoodworkswell.blogspot.com</font></a>)，Darren James及另外一些人所支持。</p><p>1.5 qooxdoo(开发中;自从2005年5月)</p><p>网址是：<a href="http://qooxdoo.sourceforge.net/"><font color="#1d58d1">http://qooxdoo.sourceforge.net/</font></a>，是另一个雄心勃勃的框架，提供宽范围的UI支持和正在开发中的基础结构特性。</p><p>·基础结构：</p><p>* DOM和事件/焦点管理的可移植的抽象。</p><p>* 调试支持。</p><p>* 易于时间调度的Timer类。 </p><p>* Getter/Setter支持。</p><p>·UI：</p><p>* 窗口小组件框架和预置的窗口小组件库。</p><p>* 布局管理器。</p><p>* 图像缓冲和可移植的PNG透明性。</p><p>·开源(LGPL)。来自多方面的贡献者。</p><p>1.6 Tibet(开发中;自从2005年6月)</p><p>网址是：<a href="http://www.technicalpursuit.com/"><font color="#1d58d1">http://www.technicalpursuit.com/</font></a>，目的是提供高度可移植的和全面的Javascript API，结果是，可能自动生成大量的客户端代码。自称是"企业级Ajax"。</p><p>·远程脚本运行在XMLHttpRequest包装之上-通过协调调用结果支持工作流管理，例如应答可以发生在只有当两个分离的调用返回时。</p><p>·URI支持。</p><p>·所有的HTTP方法-不仅是"GET"和"POST"。</p><p>·低级的协议-File://和WebDav以及HTTP。</p><p>·Web服务调用-SOAP，XML-RPC，等等。</p><p>·预置的针对Google API，Amazon API等等服务的支持。</p><p>·由高级Javascript对象组成一个巨大的库。</p><p>·许多XML操作。</p><p>·IDE和开发工具。</p><p>·开源许可(显然经过OSI认证，但是细节不多)。<br /><br /><span class="top11"><strong>2 纯Javascript：基础结构框架</strong></span></p><p></p><p>2.1 AjaxCaller(Alpha版本;自从5月2005年)</p><p>网址是：<a href="http://ajaxify.com/run/testAjaxCaller/"><font color="#1d58d1">http://ajaxify.com/run/testAjaxCaller/</font></a>，是一基本的线程安全的XMLHttpRequest包装器，主要针对Ajax新手，仍处于原始的alpha开发阶段，目前仅与AjaxPatterns的在线搜索范例一起打包。</p><p>·实现对服务器的调用(GET/POST/PUT/DELETE)，用路由到一个回叫操作的plain-text或者XML完成。</p><p>·使用过的XMLHttpRequest对象的析构。</p><p>·Response缓冲(计划的)。</p><p>·针对Ajax新手-并非强调性能优化，该库主要用于实现易读的基础代码并将提供调试支持。</p><p>·开源许可。由Michael Mahemoff(<a href="http://softwareas.com/"><font color="#1d58d1">http://softwareas.com</font></a>)(具有John Wehr和Richard Schwartz的一些思想)维护。</p><p>2.2 Flash JavaScript集成包</p><p>网址是：<a href="http://www.osflash.org/doku.php?id=flashjs"><font color="#1d58d1">http://www.osflash.org/doku.php?id=flashjs</font></a>，允许JavaScript和Flash内容的集成：</p><p>·使JavaScript能够调用ActionScript功能和反过来的实现。</p><p>·所有主要的数据类型能在这两种环境之间传递。</p><p>·开源许可。由多个开源Flash贡献者提供支持。</p><p>2.3 Google AJAXSLT(发行于2005年6月)</p><p>网址是：<a href="http://goog-ajaxslt.sourceforge.net/"><font color="#1d58d1">http://goog-ajaxslt.sourceforge.net/</font></a>，是一个Javascript框架，用来执行XSLT转换以及XPath查询。</p><p>·建立在Google地图工作基础之上。</p><p>·开源许可(BSD)。由一家创新搜索方案公司支持，自称为"Google"。</p><p>2.4 HTMLHttpRequest(Beta版；始于2005年)</p><p>HtmlHttpRequest(<a href="http://www.twinhelix.com/javascript/htmlhttprequest/"><font color="#1d58d1">http://www.twinhelix.com/javascript/htmlhttprequest/</font></a>)，它使用了XMLHttpRequest和Iframes以改进兼容性。</p><p>·测试过并能工作在:IE6/Win，IE5.5/Win，IE5/Win，IE4/Win，Mozilla/Win，Opera7/Win，Safari/Mac，IE5/Mac。</p><p>·未测试，可能能工作在：IE4/Mac，Mozilla/Mac，Opera/Other，Konqueror/Linux。你正在使用这些之一吗？作者正在请求兼容性信息。</p><p>·开源许可(LGPL)。由Twin Helix Designs(<a href="http://www.twinhelix.com/"><font color="#1d58d1">http://www.twinhelix.com/</font></a>)的Angus Turnbull维护。</p><p>2.5 交互式网站框架(自从2005年5月)</p><p>交互式网站框架(<a href="http://sourceforge.net/projects/iwf/"><font color="#1d58d1">http://sourceforge.net/projects/iwf/</font></a>，是一个项目，目的是从浏览器端对Ajax基础结构的多方面予以支持。自描述为"使用javascript，css，xml，和html来创造高度交互网站的框架。包括一个定制的针对高度可读的javascript的xml分析器。实质上，是建立基于AJAX的网站的基础，还有另外一些通用脚本"。</p><p>·线程安全的XMLHttpRequest实现。</p><p>·针对XML文档的包装器，以便你能够创建更具可读性的代码：</p><p>var node = doc.groceries.frozen[0].pizza[0].size;&lt;/pre&gt;</p><p>代替手工的导航：</p><p>var node = doc.documentElement.firstChild.firstChild.getAttribute("size");&lt;/pre&gt;</p><p>·开源许可。由Weaver(<a href="http://circaware.com|brock/"><font color="#1d58d1">http://circaware.com|Brock</font></a>)维护。</p><p>2.6 LibXMLHttpRequest(发行于2003年6月)</p><p>libXmlRequest(<a href="http://www.whitefrost.com/servlet/connector?file=reference/2003/06/17/libXmlRequest.html"><font color="#1d58d1">http://www.whitefrost.com/servlet/connector?file=reference/2003/06/17/libXmlRequest.html</font></a>)，是XMLHttpRequest的一个瘦包装器。</p><p>·getXML()和postXML()方法。</p><p>·XMLHttpRequest对象池支持。</p><p>·Response缓冲。</p><p>·可用源码(明显)，但是受标准版权的保护，由Stephen W.Coate(<a href="http://www.whitefrost.com/index.jsp"><font color="#1d58d1">http://www.whitefrost.com/index.jsp</font></a>)所维护。</p><p>2.7 RSLite(x)</p><p>网站是：<a href="http://www.ashleyit.com/rs/main.htm"><font color="#1d58d1">http://www.ashleyit.com/rs/main.htm</font></a>，是一个针对XMLHttpRequest的瘦包装器。</p><p>·一个简单的组件，作为Brent Ashley的更全面的远程脚本工作(参见Javascript远程脚本-JSRS在多语言服务器端)的一部分发行。</p><p>2.8 Sack(在开发中，自从2005年5月)</p><p>网站是：<a href="http://twilightuniverse.com/2005/05/sack-of-ajax/"><font color="#1d58d1">http://twilightuniverse.com/2005/05/sack-of-ajax/</font></a>，是一个针对XMLHttpRequest的瘦包装器。</p><p>·调用者能指定回叫函数或者回叫DOM对象。借助于回叫DOM，应答文本直接被推入到DOM中</p><p>2.9 Sarissa(发行于2月，2003年)</p><p>网站是：<a href="http://sarissa.sf.net/"><font color="#1d58d1">http://sarissa.sf.net</font></a>，是一种Javascript API，它封装了在浏览器端可以独立调用XML的功能。</p><p>·可移植的XMLHttpRequest创建</p><p>·可移植的XPath查询</p><p>·可移植的DOM操作</p><p>·可移植的XSLT</p><p>·可移植的XML串行化</p><p>·开源(GPL2.0和LGPL2.1)。来自多方面贡献者。</p><p>2.10 XHConn(发行于自从4月，2005年)</p><p>网站是：<a href="http://xkr.us/code/javascript/XHConn/"><font color="#1d58d1">http://xkr.us/code/javascript/XHConn/</font></a>，是一个对XMLHttpRequest的瘦包装器。</p><p>·例如</p><p>ew XHConn().connect("mypage.php"，"POST"，"foo=bar&amp;baz=qux"，fnWhenDone);</p><p>·开源许可。由Brad Fults所维护。<br /><br /><span class="top11"><strong>3 服务器端：多种语言</strong></span></p><p></p><p>3.1 跨平台异步的接口工具箱(5月2005年)</p><p>CPAINT：<a href="http://cpaint.sourceforge.net/"><font color="#1d58d1">http://cpaint.sourceforge.net/</font></a>，是一真正的支持PHP和ASP/Vbscript的Ajax实现和JSRS(JavaScript远程脚本)实现。CPAINT提供给你需求的代码在后台实现AJAX和JSRS，而返回的数据以JavaScript形式在前台操作，格式化和显示。这允许你创建能提供接近实时的反馈给用户的web应用程序。</p><p>·支持PHP&amp;ASP</p><p>·针对所有函数的一致的JavaScript文件</p><p>·支持远程脚本和XML</p><p>·支持本地和远程函数</p><p>·单个或者多个XMLHTTP对象</p><p>·以文本或者JavaScript XML/DOM文档对象方式返回后台数据</p><p>·能支持POST和GET请求</p><p>·后台代理函数来访问远程函数和数据</p><p>·在所有的主要浏览器上测试过</p><p>·在GNU GPL&amp;LGPL保护下发行</p><p>3.2 SAJAX(可用，但是不是1.0版本;自从3月2005年)</p><p>网站是：<a href="http://www.modernmethod.com/sajax/"><font color="#1d58d1">http://www.modernmethod.com/sajax/</font></a>，直接把调用从Javascript发送到你的服务器端语言并再次回返。例如，调用一个javascript方法x_calculateBudget()，将先到达服务器和调用一个Java calculateBudget()方法，然后以javascript方式把值返回到x_calculateBudget_cb()。</p><p>·便利从Javascript代理函数到后台操作的映射。</p><p>·能够代理对众多服务器端平台（ASP/ColdFusion/Io/Lua/Perl/PHP/Python/Ruby）的调用。</p><p>·开源许可。来自多方面贡献者。</p><p>3.3 Javascipt对象标志(JSON)和JSON-RPC</p><p>JSON(<a href="http://www.crockford.com/JSON/index.html"><font color="#1d58d1">http://www.crockford.com/JSON/index.html</font></a>)，是一个"胖的自由的XML选择"，而JSON-RPC(<a href="http://www.json-rpc.org/"><font color="#1d58d1">http://www.json-rpc.org/</font></a>)是一种远程过程协议，类似于XML-RPC，强有力支持Javascript客户。</p><p>·实现多服务器端平台(<a href="http://www.json-rpc.org/impl.xhtml"><font color="#1d58d1">http://www.json-rpc.org/impl.xhtml</font></a>)：Java，Python，Ruby，Perl。</p><p>·针对每种平台有独立的打包和许可，如JSON-RPC-Java(<a href="http://oss.metaparadigm.com/jsonrpc/"><font color="#1d58d1">http://oss.metaparadigm.com/jsonrpc/</font></a>)。</p><p>3.4 Javascript远程脚本(JSRS)(自从2000年)</p><p>网址是：<a href="http://www.ashleyit.com/rs/jsrs/test.htm"><font color="#1d58d1">http://www.ashleyit.com/rs/jsrs/test.htm</font></a>，直接把调用从Javascript发送到你的服务器端语言并再次回返。</p><p>·知名的浏览器：IE4+，NS4.x，NS6.x，Mozilla，Opera7和Galeon。</p><p>·服务器端支持：ASP，ColdFusion，PerlCGI，PHP,Python和JSP(servlet)。</p><p>·开源许可。由Brent Ashley(<a href="http://www.ashleyit.com/"><font color="#1d58d1">http://www.ashleyit.com/</font></a>)提供支持。</p><p><strong>4 服务器端：Java</strong></p><p>注意：许多现有的框架最近正在添加Java支持(例如struts)，我将在后面指出。</p><p>4.1 WebORB for Java(自从2005年8月)</p><p>网址：<a href="http://www.themidnightcoders.com/weborb/aboutWeborb.htm"><font color="#1d58d1">http://www.themidnightcoders.com/weborb/aboutWeborb.htm</font></a>，是一个平台，支持开发AJAX和基于Flash的胖客户端应用程序，并可以把它们与Java对象和XML Web服务相系起来。在线举例(http：//www.themidnightcoders.com/examples)</p><p>·WebORB包括一个称作丰富的客户系统(<a href="http://www.themidnightcoders.com/rcs/index.htm"><font color="#1d58d1">http://www.themidnightcoders.com/rcs/index.htm</font></a>)的客户端库。该丰富的客户系统提供一简单的在线api来绑定到并调用任何Java对象，XML Web服务或者EJB上的方法。</p><p>·支持同步的和异步的方法调用。</p><p>·并不要求在服务器端代码上作任何修改，不需要定制方法属性，特别的签名或者参数类型。★不要求设计时生成代理。</p><p>·同步调用返回来自于该调用(不需要回叫)的数据。异步的调用依赖于一个回叫实现。</p><p>·任何服务器端方法能被同步地或者异步地调用。</p><p>·客户应用程序能向服务器对象请求指定的活动方式。结果，对象能被轻易地创建而不需任何特殊的编程。</p><p>·提供一个特定API来处理数据库查询结果-服务器代码能返回Data集合或者Data表，而客户端以一个特殊RecordSet JavaScript对象来显示这个结果。该对象提供一个方法以检索列名和行数据。</p><p>·支持数据分页技术。客户应用程序能检索页面中的数据。</p><p>·支持所有的服务器端参数类型并返回值-原型，字符串，复合类型，数组，本机.net集合，远程参考。</p><p>·共有两种版本可用：标准版(自由)和专业版(商业许可)</p><p>4.2 Echo 2(自从3月2005年)</p><p>网址是：<a href="http://www.nextapp.com/products/echo2/"><font color="#1d58d1">http://www.nextapp.com/products/echo2/</font></a>，允许你用纯Java代码编写Ajax应用软件(范例(<a href="http://demo.nextapp.com/InteractiveTest/ia"><font color="#1d58d1">http://demo.nextapp.com/InteractiveTest/ia</font></a>))。</p><p>自动地生成HTML和Javascript。</p><p>·协调浏览器和服务器之间的消息。消息形式为XML。</p><p>·如果需要，可以手工编写定制的Javascript部件。</p><p>·开源许可(Mozilla公共许可或者GNU LGPL)。源于Next App,Inc.(<a href="http://www.nextapp.com/"><font color="#1d58d1">http://www.nextapp.com/</font></a>)。</p><p>4.3 Direct Web Remoting (DWR)(2005年)</p><p>网址是：<a href="http://www.getahead.ltd.uk/dwr/"><font color="#1d58d1">http://www.getahead.ltd.uk/dwr/</font></a>，是一个框架，用于直接从Javascript代码中调用Java方法。</p><p>·象SAJAX，能把Javascript中的调用传递到Java方法，并返回到Javascript回叫。</p><p>·能与任何web框架（Struts，Tapestry，等等）一起使用。</p><p>·开源许可(Apache(<a href="http://www.apache.org/LICENSE.txt"><font color="#1d58d1">http://www.apache.org/LICENSE.txt</font></a>))。由Joe Walker(<a href="http://www.getahead.ltd.uk/sg/space/joe/"><font color="#1d58d1">http://www.getahead.ltd.uk/sg/space/joe/</font></a>)所支持。被加入到WebWork(<a href="http://www.opensymphony.com/webwork/"><font color="#1d58d1">http://www.opensymphony.com/webwork/</font></a>)版本。</p><p>4.4 SWATO(2005年)</p><p>网址是：<a href="http://swato.dev.java.net/"><font color="#1d58d1">http://swato.dev.java.net/</font></a>，是一套可重用的和良好集成的Java/JavaScript库，它实现了一种更容易的方式来改变你的web应用程序的交互，它是通过AJAX方式实现。</p><p>·服务器端Java库能被容易地配置到所有的Servlet 2.3+匹配的容器中。</p><p>·客户端JavaScript库能工作在支持HttpXMLRequest的各种浏览器中。</p><p>·使用JSON来在服务器端编组你的POJO数据。这样你能存取在任何JavaScript环境(HTML，XUL，SVG)中的远程数据，这种存取可以容易地通过硬编码或者与某种成熟的JavaScript库集成来实现。</p><p>·提供一个简单的接口来使你的JavaScript代码可以与暴露在客户端的远程POJO交互(RPC等)。</p><p>·使用web.xml中的&lt;servlet&gt;和&lt;filter&gt;的容易且灵活的配置，并能(但不是依赖)与Spring集成到一起。</p><p>·提供了几个可帮助你快速开发web应用程序的组件(如自动完成的文本框，在线表单，在线列表，等等)。<br /><br /><span class="top11"><strong>5 服务器端：Lisp</strong></span></p><p></p><p>5.1 CL-Ajax</p><p>网址：<a href="http://cliki.net/cl-ajax"><font color="#1d58d1">http://cliki.net/cl-ajax</font></a>，实现Javascript直接调用服务器端Lisp函数。</p><p>·如下输出函数：</p><p>(export-函数 #’my-函数) </p><p>·可以产生带有参数的Javascript代理。</p><p>·能回叫Javascript函数或者DOM对象。</p><p>·可以被集成进SAJAX。</p><p>·开源(定制，非常灵活，许可)。由[Richard Newman](<a href="http://www.holygoat.co.uk/"><font color="#1d58d1">http://www.holygoat.co.uk/</font></a>)所维护。</p><p><strong>6 服务器端：.NET</strong></p><p>6.1 WebORB for.NET(自从8月2005年)</p><p>网址：<a href="http://www.themidnightcoders.com/weborb/aboutWeborb.htm"><font color="#1d58d1">http://www.themidnightcoders.com/weborb/aboutWeborb.htm</font></a>，是一个平台，用于开发AJAX和基于Flash的胖客户端应用程序，并能把它们连接到.NET对象和XML Web服务。(在线举例(<a href="http://www.themidnightcoders.com/examples"><font color="#1d58d1">http://www.themidnightcoders.com/examples</font></a>))</p><p>·WebORB包括一个客户端库，名叫Rich Client System(<a href="http://www.themidnightcoders.com/rcs/index.htm"><font color="#1d58d1">http://www.themidnightcoders.com/rcs/index.htm</font></a>)。Rich Client System提供一简单的在线api以绑定到和调用任何.NET对象或者XML Web服务上的任何方法。</p><p>·支持同步和异步的方法调用</p><p>·并不要求在服务器端代码上作任何修改，不需要定制方法属性，特别的签名或者参数类型。**不要求设计时代理生成。</p><p>·同步调用返回来自于该调用的数据(不需要回叫)。异步的调用依赖于一个回叫实现。</p><p>·任何服务器端方法能被同步地或者异步地调用。</p><p>·客户应用程序能向服务器对象请求指定的活动方式。结果，对象能被轻易地创建而不需任何特殊的编程。</p><p>·提供一个特定API来处理数据库查询结果-服务器代码能返回DataSet或者DataTable，而客户端以一个特殊RecordSet JavaScript对象来显示这个结果。该对象提供一个方法以检索列名和行数据</p><p>·支持数据页面技术。客户端应用程序能检索页面中的数据。</p><p>·支持所有的服务器端参数类型并返回值-原型，字符串，复合类型，数组，本机.net集合，远程参考</p><p>·共有两种版本可用的：标准版(自由)和专业版(商业许可)</p><p>6.2 Ajax.NET(自从3月2005年)</p><p>网址是：<a href="http://ajax.schwarz-interactive.de/"><font color="#1d58d1">http://ajax.schwarz-interactive.de/</font></a>，是一个库，实现从Javascript到服务器端.NET的存取。</p><p>·象SAJAX，能把Javascript中的调用传递到.NET方法，并返回到Javascript回叫。</p><p>·能存取来自于JavaScript的会话数据。</p><p>·缓存结果</p><p>·自由使用，可用的源码，未指定使用许可。由Michael Schwarz(<a href="http://weblogs.asp.net/mschwarz/"><font color="#1d58d1">http://weblogs.asp.net/mschwarz/</font></a>)所维护。</p><p>·不允许改变源代码，用属性标记方法</p><p>·完整的类支持以返回客户端JavaScript值</p><p>·使用HtmlControls来进行输入和返回值</p><p>·可以返回数据表，数据集，数据视图，数组和集合</p><p><strong>7 服务器端：PHP</strong></p><p>7.1 AjaxAC(自从2005年4月)</p><p>网址是：<a href="http://ajax.zervaas.com.au/"><font color="#1d58d1">http://ajax.zervaas.com.au/</font></a>，用单个的PHP类封装了完整的应用程序。</p><p>·所有的应用程序代码是自包含在单个类中(附加另外一些JavaScript库)</p><p>·干净利索地调用PHP文件/HTML页面。只需创建应用程序类，然后参照应用程序JavaScript和依附任何需要的HTML元素到该应用程序。 </p><p>·容易地处理JavaScript事件的内嵌功能</p><p>·创建子需要并处理它们的内嵌功能</p><p>·允许定制的配置值，因此某些单元能在运行时间设置</p><p>·无凌乱的JavaScript代码夹杂在调用HTML的代码中-所有的事件是被动态依附的</p><p>·由于以上两个原因容易和模板引擎集成到一起</p><p>·容易钩到（hook in to）已有的PHP类或者MySQL数据库以返回来自于子需求的数据</p><p>·能够容易地进一步生成JavaScript对象的可扩展的窗口小组件结构(但是还需要做一些工作)</p><p>背景：</p><p>·开源许可(Apache2.0)。由Zervaas Enterprises(<a href="http://ajax.zervaas.com.au/"><font color="#1d58d1">http://ajax.zervaas.com.au/</font></a>)支持</p><p>7.2 JPSpan</p><p>网址是：<a href="http://jpspan.sourceforge.net/wiki/doku.php"><font color="#1d58d1">http://jpspan.sourceforge.net/wiki/doku.php</font></a>，直接把Javascript调用传递到PHP函数。</p><p>·进行了严肃的单元测试。</p><p>·开源许可(PHP)。</p><p>7.3 XAJAX</p><p>网址是：<a href="http://xajax.sf.net/"><font color="#1d58d1">http://xajax.sf.net</font></a>，直接把Javascript调用传递到PHP函数。</p><p>·使用Javascript代理来调用PHP脚本。</p><p>·开源。由J.Max Wilson所创。</p><p>8 服务器端：Ruby</p><p>Ruby On Rails(<a href="http://www.rubyonrails.org/"><font color="#1d58d1">http://www.rubyonrails.org/</font></a>)是一个通常的强力支持Ajax的web框架：</p><p>·当Ajax出现的时候Rails还处于其发展的早期，因此Ajax可能逐渐成为Rails框架的核心。</p><p>·生成浏览器中大多数/全部的窗口小组件和动画的Javascript脚本。</p><p>·支持服务器端调用。</p><p>·调度支持。　</p><p>·开源许可。</p><img src ="http://www.blogjava.net/TrampEagle/aggbug/27902.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-01-13 12:50 <a href="http://www.blogjava.net/TrampEagle/articles/27902.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>AJAX开发简略 (第二部分) </title><link>http://www.blogjava.net/TrampEagle/articles/27853.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Fri, 13 Jan 2006 02:01:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/27853.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/27853.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/27853.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/27853.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/27853.html</trackback:ping><description><![CDATA[
		<p>引自：<a href="http://blog.chinaunix.com/u/12958/?u=http://blog.chinaunix.com/u/12958/showart.php?id=67064">http://blog.chinaunix.com/u/12958/?u=http://blog.chinaunix.com/u/12958/showart.php?id=67064</a><br /><br /><span class="h1b">AJAX开发简略 (第二部分)</span><br /><!-- 提取技术文章 --><br /></p>
		<div class="beas">
				<img height="1" alt="" src="http://dev2dev.bea.com.cn/images/dot6B6B6B.gif" width="100%" />
		</div>
		<p>
				<a>AJAX开发</a>
		</p>
		<ul>
				<li>
						<a href="http://dev2dev.bea.com.cn/bbsdoc/20051114125.html#a71">
								<font color="#800080">7.1、AJAX应用到的技术</font>
						</a>
				</li>
				<li>
						<a href="http://dev2dev.bea.com.cn/bbsdoc/20051114125.html#a72">
								<font color="#800080">7.2、AJAX开发框架</font>
						</a>
				</li>
				<li>
						<a href="http://dev2dev.bea.com.cn/bbsdoc/20051114125.html#a73">
								<font color="#800080">7.3、简单的示例</font>
						</a>
				</li>
				<li>
						<a href="http://dev2dev.bea.com.cn/bbsdoc/20051114125.html#a74">
								<font color="#800080">7.4、文档对象模型（DOM）</font>
						</a>
				</li>
				<li>
						<a href="http://dev2dev.bea.com.cn/bbsdoc/20051114125.html#a75">
								<font color="#800080">7.5、处理XML文档</font>
						</a>
				</li>
				<li>
						<a href="http://dev2dev.bea.com.cn/bbsdoc/20051114125.html#a8">
								<font color="#800080">参考文章</font>
						</a>
				</li>
		</ul>
		<p>
				<a>
						<strong>七、AJAX开发</strong>
				</a>
				<br />　　到这里，已经可以清楚的知道AJAX是什么，AJAX能做什么，AJAX什么地方不好。如果你觉得AJAX真的能给你的开发工作带来改进的话，那么继续看看怎么使用AJAX吧。<a name="a71"></a></p>
		<p>
				<strong>
						<a>7.1</a>、AJAX应用到的技术</strong>
				<br />　　AJAX涉及到的7项技术中，个人认为Javascript、XMLHttpRequest、DOM、XML比较有用。<br /><br /><a>A</a>、XMLHttpRequest对象<br />　　XMLHttpRequest是XMLHTTP组件的对象，通过这个对象，AJAX可以像桌面应用程序一样只同服务器进行数据层面的交换，而不用每次都刷新界面，也不用每次将数据处理的工作都交给服务器来做；这样既减轻了服务器负担又加快了响应速度、缩短了用户等待的时间。 </p>
		<p>　　IE5.0开始，开发人员可以在Web页面内部使用XMLHTTP ActiveX组件扩展自身的功能，不用从当前的Web页面导航就可以直接传输数据到服务器或者从服务器接收数据。,Mozilla1.0以及NetScape7则是创建继承XML的代理类XMLHttpRequest；对于大多数情况，XMLHttpRequest对象和XMLHTTP组件很相似，方法和属性类似，只是部分属性不同。</p>
		<pre class="precode">XMLHttpRequest对象初始化：
&lt;script language=”javascript”&gt;
var http_request = false;
//IE浏览器
http_request = new ActiveXObject("Msxml2.XMLHTTP");
http_request = new ActiveXObject("Microsoft.XMLHTTP");
//Mozilla浏览器
http_request = new XMLHttpRequest();
&lt;/script&gt;</pre>
		<p>　　XMLHttpRequest对象的方法：</p>
		<p>
		</p>
		<table cellspacing="1" cellpadding="4" bgcolor="#000000">
				<tbody>
						<tr bgcolor="#ffffff">
								<td valign="top" width="489">方法</td>
								<td valign="top" width="221">描述</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td valign="top" width="489">abort()</td>
								<td valign="top" width="221">
										<p>停止当前请求</p>
								</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td valign="top" width="489">getAllResponseHeaders()</td>
								<td valign="top" width="221">
										<p>作为字符串返回完整的headers</p>
								</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td valign="top" width="489">getResponseHeader("headerLabel")</td>
								<td valign="top" width="221">
										<p>作为字符串返回单个的header标签</p>
								</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td valign="top" width="489">open("method","URL"[,asyncFlag[,"userName"[, "password"]]])</td>
								<td valign="top" width="221">设置未决的请求的目标 URL，方法，和其他参数</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td valign="top" width="489">send(content)</td>
								<td valign="top" width="221">发送请求</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td valign="top" width="489">setRequestHeader("label", "value")</td>
								<td valign="top" width="221">设置header并和请求一起发送</td>
						</tr>
				</tbody>
		</table>
		<p>　　XMLHttpRequest对象的属性：</p>
		<p>
		</p>
		<table cellspacing="1" cellpadding="4" bgcolor="#000000">
				<tbody>
						<tr bgcolor="#ffffff">
								<td valign="top" width="159">属性</td>
								<td valign="top" width="551">描述</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td valign="top" width="159">onreadystatechange</td>
								<td valign="top" width="551">状态改变的事件触发器</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td valign="top" width="159">readyState</td>
								<td valign="top" width="551">对象状态(integer): 
<p></p><br />0 = 未初始化 <br />1 = 读取中<br />2 = 已读取<br />3 = 交互中<br />4 = 完成</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td valign="top" width="159">responseText</td>
								<td valign="top" width="551">服务器进程返回数据的文本版本</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td valign="top" width="159">responseXML</td>
								<td valign="top" width="551">服务器进程返回数据的兼容DOM的XML文档对象</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td valign="top" width="159">status</td>
								<td valign="top" width="551">服务器返回的状态码, 如：404 = "文件未找到" 、200 ="成功"</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td valign="top" width="159">statusText</td>
								<td valign="top" width="551">服务器返回的状态文本信息</td>
						</tr>
				</tbody>
		</table>
		<a>
				<br />B</a>、Javascript<br />　　 Javascript一直被定位为客户端的脚本语言，应用最多的地方是表单数据的校验。现在，可以通过Javascript操作XMLHttpRequest，来跟数据库打交道。<a><br /><br />C</a>、DOM<br />　　 DOM（Document Object Model）是提供给HTML和XML使用的一组API，提供了文件的表述结构，并可以利用它改变其中的内容和可见物。脚本语言通过DOM才可以跟页面进行交互。Web开发人员可操作及建立文件的属性、方法以及事件都以对象来展现。比如，document就代表页面对象本身。<br /><br /><a>D</a>、XML<br />　　通过XML（Extensible Markup Language），可以规范的定义结构化数据，是网上传输的数据和文档符合统一的标准。用XML表述的数据和文档，可以很容易的让所有程序共享。<a name="a72"></a><br /><br /><strong><a>7.2</a>、AJAX开发框架</strong><br />　　这里，我们通过一步步的解析，来形成一个发送和接收XMLHttpRequest请求的程序框架。AJAX实质上也是遵循Request/Server模式，所以这个框架基本的流程也是：对象初始化à发送请求à服务器接收à服务器返回à客户端接收à修改客户端页面内容。只不过这个过程是异步的。<br /><br /><a>A</a>、初始化对象并发出XMLHttpRequest请求<br />　　为了让Javascript可以向服务器发送HTTP请求，必须使用XMLHttpRequest对象。使用之前，要先将XMLHttpRequest对象实例化。之前说过，各个浏览器对这个实例化过程实现不同。IE以ActiveX控件的形式提供，而Mozilla等浏览器则直接以XMLHttpRequest类的形式提供。为了让编写的程序能够跨浏览器运行，要这样写： <pre class="precode">if (window.XMLHttpRequest) { // Mozilla, Safari, ...
       http_request = new XMLHttpRequest();
  } 
  else if (window.ActiveXObject) { // IE
       http_request = new ActiveXObject("Microsoft.XMLHTTP");
}</pre><p>　　有些版本的Mozilla浏览器处理服务器返回的未包含XML mime-type头部信息的内容时会出错。因此，要确保返回的内容包含text/xml信息。 </p><pre class="precode">http_request = new XMLHttpRequest();
http_request.overrideMimeType('text/xml');</pre><p>B、指定响应处理函数<br />　　接下来要指定当服务器返回信息时客户端的处理方式。只要将相应的处理函数名称赋给XMLHttpRequest对象的onreadystatechange属性就可以了。比如： </p><p></p><pre class="precode">http_request.onreadystatechange = processRequest;</pre><p>　　需要指出的时，这个函数名称不加括号，不指定参数。也可以用Javascript即时定义函数的方式定义响应函数。比如：</p><p class="precode">http_request.onreadystatechange = function() { };</p><pre></pre><p><a>C</a>、发出HTTP请求 </p><p>　　指定响应处理函数之后，就可以向服务器发出HTTP请求了。这一步调用XMLHttpRequest对象的open和send方法。</p><pre class="precode">http_request.open('GET', 'http://www.example.org/some.file', true);
http_request.send(null);</pre><p>　　open的第一个参数是HTTP请求的方法，为Get、Post或者Head。</p><p>　　open的第二个参数是目标URL。基于安全考虑，这个URL只能是同网域的，否则会提示“没有权限”的错误。这个URL可以是任何的URL，包括需要服务器解释执行的页面，不仅仅是静态页面。目标URL处理请求XMLHttpRequest请求则跟处理普通的HTTP请求一样，比如JSP可以用request.getParameter(“”)或者request.getAttribute(“”)来取得URL参数值。</p><p>　　open的第三个参数只是指定在等待服务器返回信息的时间内是否继续执行下面的代码。如果为True，则不会继续执行，直到服务器返回信息。默认为True。</p><p>　　按照顺序，open调用完毕之后要调用send方法。send的参数如果是以Post方式发出的话，可以是任何想传给服务器的内容。不过，跟form一样，如果要传文件或者Post内容给服务器，必须先调用setRequestHeader方法，修改MIME类别。如下：</p><pre class="precode">http_request.setRequestHeader(“Content-Type”,”application/x-www-form-urlencoded”);</pre><p>　　这时资料则以查询字符串的形式列出，作为sned的参数，例如：</p><pre class="precode">name=value&amp;anothername=othervalue&amp;so=on</pre><p>D、处理服务器返回的信息 <br />　　在第二步我们已经指定了响应处理函数，这一步，来看看这个响应处理函数都应该做什么。 </p><p>　　首先，它要检查XMLHttpRequest对象的readyState值，判断请求目前的状态。参照前文的属性表可以知道，readyState值为4的时候，代表服务器已经传回所有的信息，可以开始处理信息并更新页面内容了。如下：</p><pre class="precode">if (http_request.readyState == 4) {
    // 信息已经返回，可以开始处理
} else {
    // 信息还没有返回，等待
}</pre><p>　　服务器返回信息后，还需要判断返回的HTTP状态码，确定返回的页面没有错误。所有的状态码都可以在<a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html"><font color="#0000ff">W3C</font></a>的官方网站上查到。其中，200代表页面正常。</p><pre class="precode">if (http_request.status == 200) {
    // 页面正常，可以开始处理信息
} else {
    // 页面有问题
}
</pre><p>　　XMLHttpRequest对成功返回的信息有两种处理方式：<br />　　 responseText：将传回的信息当字符串使用；<br />　　 responseXML：将传回的信息当XML文档使用，可以用DOM处理。</p><p><a>E</a>、一个初步的开发框架<br />　　总结上面的步骤，我们整理出一个初步的可用的开发框架，供以后调用；这里，将服务器返回的信息用window.alert以字符串的形式显示出来： </p><pre class="precode">&lt;script language="javascript"&gt;
	var http_request = false;
	function send_request(url) {//初始化、指定处理函数、发送请求的函数
		http_request = false;
		//开始初始化XMLHttpRequest对象
		if(window.XMLHttpRequest) { //Mozilla 浏览器
			http_request = new XMLHttpRequest();
			if (http_request.overrideMimeType) {//设置MiME类别
				http_request.overrideMimeType("text/xml");
			}
		}
		else if (window.ActiveXObject) { // IE浏览器
			try {
				http_request = new ActiveXObject("Msxml2.XMLHTTP");
			} catch (e) {
				try {
					http_request = new ActiveXObject("Microsoft.XMLHTTP");
				} catch (e) {}
			}
		}
		if (!http_request) { // 异常，创建对象实例失败
			window.alert("不能创建XMLHttpRequest对象实例.");
			return false;
		}
		http_request.onreadystatechange = processRequest;
		// 确定发送请求的方式和URL以及是否同步执行下段代码
		http_request.open("GET", url, true);
		http_request.send(null);
	}
	// 处理返回信息的函数
    function processRequest() {
        if (http_request.readyState == 4) { // 判断对象状态
            if (http_request.status == 200) { // 信息已经成功返回，开始处理信息
                alert(http_request.responseText);
            } else { //页面不正常
                alert("您所请求的页面有异常。");
            }
        }
    }
&lt;/script&gt;<a name="a73"></a></pre><p><strong>7.3、简单的示例</strong><br />　　接下来，我们利用上面的开发框架来做两个简单的应用。<br /><br /><a>A</a>、数据校验<br />　　在用户注册的表单中，经常碰到要检验待注册的用户名是否唯一。传统的做法是采用window.open的弹出窗口，或者window. showModalDialog的对话框。不过，这两个都需要打开窗口。采用AJAX后，采用异步方式直接将参数提交到服务器，用window.alert将服务器返回的校验信息显示出来。代码如下： </p><p>　　在&lt;body&gt;&lt;/body&gt;之间增加一段form表单代码：</p><pre class="precode">&lt;form name="form1" action="" method="post"&gt;<br />
  用户名：&lt;input type="text" name="username" value=""&gt;&amp;nbsp;<br />
  &lt;input type="button" name="check" value="唯一性检查" onClick="userCheck()"&gt;<br />
  &lt;input type="submit" name="submit" value="提交"&gt;<br />
&lt;/form&gt;</pre><p>　　在开发框架的基础上再增加一个调用函数：</p><pre class="precode">function userCheck() {
	var f = document.form1;
	var username = f.username.value;
	if(username=="") {
		window.alert("用户名不能为空。");
		f.username.focus();
		return false;
	}
	else {
		send_request('sample1_2.jsp?username='+username);
	}
}
</pre><p>　　看看sample1_2.jsp做了什么：</p><pre class="precode">&lt;%@ page contentType="text/html; charset=gb2312" errorPage="" %&gt;
&lt;%
String username = request.getParameter("username");
if("educhina".equals(username)) out.print("用户名已经被注册，请更换一个用户名。");
else out.print("用户名尚未被使用，您可以继续。");
%&gt;</pre><p>　　运行一下，嗯，没有弹出窗口，没有页面刷新，跟预想的效果一样。如果需要的话，可以在sample1_2.jsp中实现更复杂的功能。最后，只要将反馈信息打印出来就可以了。</p><p align="center"><img src="http://dev2dev.bea.com.cn/images/image051114016.jpg" /><br /><img src="http://dev2dev.bea.com.cn/images/image051114018.jpg" /></p><p><a>B</a>、级联菜单<br />　　我们在第五部分提到利用AJAX改进级联菜单的设计。接下来，我们就演示一下如何“按需取数据”。 </p><p>　　首先，在&lt;body&gt;&lt;/body&gt;中间增加如下HTML代码：</p><pre class="precode">&lt;table width="200" border="0" cellspacing="0" cellpadding="0"&gt;
    &lt;tr&gt;
        &lt;td height="20"&gt;
			&lt;a href="javascript:void(0)" onClick="showRoles('pos_1')"&gt;经理室&lt;/a&gt;
		&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr style="display:none"&gt;
        &lt;td height="20" id="pos_1"&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td height="20"&gt;
			&lt;a href="javascript:void(0)" onClick="showRoles('pos_2')"&gt;开发部&lt;/a&gt;
		&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr style="display:none "&gt;
        &lt;td id="pos_2" height="20"&gt; &lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;
</pre><p>　　在框架的基础上增加一个响应函数showRoles(obj)：</p><pre class="precode">//显示部门下的岗位
function showRoles(obj) {
	document.getElementById(obj).parentNode.style.display = "";
	document.getElementById(obj).innerHTML = "正在读取数据..."
	currentPos = obj;
	send_request("sample2_2.jsp?playPos="+obj);
}
</pre><p>　　修改框架的processRequest函数：</p><pre class="precode">// 处理返回信息的函数
function processRequest() {
  if (http_request.readyState == 4) { // 判断对象状态
    if (http_request.status == 200) { // 信息已经成功返回，开始处理信息
	document.getElementById(currentPos).innerHTML = http_request.responseText;
    } else { //页面不正常
      alert("您所请求的页面有异常。");
    }
  }
}
</pre><p>　　最后就是smaple2_2.jsp了：</p><pre class="precode">&lt;%@ page contentType="text/html; charset=gb2312" errorPage="" %&gt;<br />&lt;%<br />String playPos = request.getParameter("playPos");
if("pos_1".equals(playPos)) 
   out.print("&amp;nbsp;&amp;nbsp;总经理&lt;br&gt;&amp;nbsp;&amp;nbsp;副总经理");
else if("pos_2".equals(playPos)) 
   out.println("&amp;nbsp;&amp;nbsp;总工程师&lt;br&gt;&amp;nbsp;&amp;nbsp;软件工程师");<br />%&gt;
</pre><p>　　运行一下看看效果：</p><p align="center"><img src="http://dev2dev.bea.com.cn/images/image051114024.jpg" /><img src="http://dev2dev.bea.com.cn/images/image051114026.jpg" /><a name="a74"></a></p><p><strong><a>7.4</a>、文档对象模型（DOM）</strong><br />　　文档对象模型（DOM）是表示文档（比如HTML和XML）和访问、操作构成文档的各种元素的应用程序接口（API）。一般的，支持Javascript的所有浏览器都支持DOM。本文所涉及的DOM，是指W3C定义的标准的文档对象模型，它以树形结构表示HTML和XML文档，定义了遍历这个树和检查、修改树的节点的方法和属性。<br /><br />7.4.1、DOM眼中的HTML文档：树<br />　　在DOM眼中，HTML跟XML一样是一种树形结构的文档，&lt;html&gt;是根（root）节点，&lt;head&gt;、&lt;title&gt;、&lt;body&gt;是&lt;html&gt;的子（children）节点，互相之间是兄弟（sibling）节点；&lt;body&gt;下面才是子节点&lt;table&gt;、&lt;span&gt;、&lt;p&gt;等等。如下图： </p><p>　　<img src="http://dev2dev.bea.com.cn/images/image051114027.gif" /></p><p>　　这个是不是跟XML的结构有点相似呢。不同的是，HTML文档的树形主要包含表示元素、标记的节点和表示文本串的节点。</p><p>7.4.2、HTML文档的节点<br />　　DOM下，HTML文档各个节点被视为各种类型的Node对象。每个Node对象都有自己的属性和方法，利用这些属性和方法可以遍历整个文档树。由于HTML文档的复杂性，DOM定义了nodeType来表示节点的类型。这里列出Node常用的几种节点类型： 
</p><table cellspacing="1" cellpadding="4" bgcolor="#000000"><tbody><tr bgcolor="#ffffff"><td valign="top" width="159">接口</td><td valign="top" width="322">nodeType常量</td><td valign="top" width="113">nodeType值</td><td valign="top" width="117">备注</td></tr><tr bgcolor="#ffffff"><td valign="top" width="159">Element</td><td valign="top" width="322">Node.ELEMENT_NODE</td><td valign="top" width="113">1</td><td valign="top" width="117">元素节点</td></tr><tr bgcolor="#ffffff"><td valign="top" width="159">Text</td><td valign="top" width="322">Node.TEXT_NODE</td><td valign="top" width="113">3</td><td valign="top" width="117">文本节点</td></tr><tr bgcolor="#ffffff"><td valign="top" width="159">Document</td><td valign="top" width="322">Node.DOCUMENT_NODE</td><td valign="top" width="113">9</td><td valign="top" width="117">document</td></tr><tr bgcolor="#ffffff"><td valign="top" width="159">Comment</td><td valign="top" width="322">Node.COMMENT_NODE</td><td valign="top" width="113">8</td><td valign="top" width="117">注释的文本</td></tr><tr bgcolor="#ffffff"><td valign="top" width="159">DocumentFragment</td><td valign="top" width="322">Node.DOCUMENT_FRAGMENT_NODE</td><td valign="top" width="113">11</td><td valign="top" width="117">document片断</td></tr><tr bgcolor="#ffffff"><td valign="top" width="159">Attr</td><td valign="top" width="322">Node.ATTRIBUTE_NODE</td><td valign="top" width="113">2</td><td valign="top" width="117">节点属性</td></tr></tbody></table><p>　　DOM树的根节点是个Document对象，该对象的documentElement属性引用表示文档根元素的Element对象（对于HTML文档，这个就是&lt;html&gt;标记）。Javascript操作HTML文档的时候，document即指向整个文档，&lt;body&gt;、&lt;table&gt;等节点类型即为Element。Comment类型的节点则是指文档的注释。具体节点类型的含义，请参考《Javascript权威指南》，在此不赘述。</p><p>　　Document定义的方法大多数是生产型方法，主要用于创建可以插入文档中的各种类型的节点。常用的Document方法有：</p><p></p><table cellspacing="1" cellpadding="4" bgcolor="#000000"><tbody><tr bgcolor="#ffffff"><td valign="top" width="204">方法</td><td valign="top" width="506">描述</td></tr><tr bgcolor="#ffffff"><td valign="top" width="204">createAttribute()</td><td valign="top" width="506">用指定的名字创建新的Attr节点。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="204">createComment()</td><td valign="top" width="506">用指定的字符串创建新的Comment节点。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="204">createElement()</td><td valign="top" width="506">用指定的标记名创建新的Element节点。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="204">createTextNode()</td><td valign="top" width="506">用指定的文本创建新的TextNode节点。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="204">getElementById()</td><td valign="top" width="506">返回文档中具有指定id属性的Element节点。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="204">getElementsByTagName()</td><td valign="top" width="506">返回文档中具有指定标记名的所有Element节点。</td></tr></tbody></table><p>　　对于Element节点，可以通过调用getAttribute()、setAttribute()、removeAttribute()方法来查询、设置或者删除一个Element节点的性质，比如&lt;table&gt;标记的border属性。下面列出Element常用的属性：</p><p></p><table cellspacing="1" cellpadding="4" bgcolor="#000000"><tbody><tr bgcolor="#ffffff"><td valign="top" width="99">属性</td><td valign="top" width="611">描述</td></tr><tr bgcolor="#ffffff"><td valign="top" width="99">tagName</td><td valign="top" width="611">元素的标记名称，比如&lt;p&gt;元素为P。HTML文档返回的tabName均为大写。</td></tr></tbody></table><p>　　Element常用的方法：</p><p></p><table cellspacing="1" cellpadding="4" bgcolor="#000000"><tbody><tr bgcolor="#ffffff"><td valign="top" width="204">方法</td><td valign="top" width="506">描述</td></tr><tr bgcolor="#ffffff"><td valign="top" width="204">getAttribute()</td><td valign="top" width="506">以字符串形式返回指定属性的值。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="204">getAttributeNode()</td><td valign="top" width="506">以Attr节点的形式返回指定属性的值。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="204">getElementsByTabName()</td><td valign="top" width="506">返回一个Node数组，包含具有指定标记名的所有Element节点的子孙节点，其顺序为在文档中出现的顺序。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="204">hasAttribute()</td><td valign="top" width="506">如果该元素具有指定名字的属性，则返回true。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="204">removeAttribute()</td><td valign="top" width="506">从元素中删除指定的属性。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="204">removeAttributeNode()</td><td valign="top" width="506">从元素的属性列表中删除指定的Attr节点。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="204">setAttribute()</td><td valign="top" width="506">把指定的属性设置为指定的字符串值，如果该属性不存在则添加一个新属性。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="204">setAttributeNode()</td><td valign="top" width="506">把指定的Attr节点添加到该元素的属性列表中。</td></tr></tbody></table><p>　　Attr对象代表文档元素的属性，有name、value等属性，可以通过Node接口的attributes属性或者调用Element接口的getAttributeNode()方法来获取。不过，在大多数情况下，使用Element元素属性的最简单方法是getAttribute()和setAttribute()两个方法，而不是Attr对象。 </p><p>7.4.3、使用DOM操作HTML文档<br />　　Node对象定义了一系列属性和方法，来方便遍历整个文档。用parentNode属性和childNodes[]数组可以在文档树中上下移动；通过遍历childNodes[]数组或者使用firstChild和nextSibling属性进行循环操作，也可以使用lastChild和previousSibling进行逆向循环操作，也可以枚举指定节点的子节点。而调用appendChild()、insertBefore()、removeChild()、replaceChild()方法可以改变一个节点的子节点从而改变文档树。 </p><p>　　需要指出的是，childNodes[]的值实际上是一个NodeList对象。因此，可以通过遍历childNodes[]数组的每个元素，来枚举一个给定节点的所有子节点；通过递归，可以枚举树中的所有节点。下表列出了Node对象的一些常用属性和方法：</p><p>　　Node对象常用属性：</p><p></p><table cellspacing="1" cellpadding="4" bgcolor="#000000"><tbody><tr bgcolor="#ffffff"><td valign="top" width="114">属性</td><td valign="top" width="596">描述</td></tr><tr bgcolor="#ffffff"><td valign="top" width="114">attributes</td><td valign="top" width="596">如果该节点是一个Element，则以NamedNodeMap形式返回该元素的属性。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="114">childNodes</td><td valign="top" width="596">以Node[]的形式存放当前节点的子节点。如果没有子节点，则返回空数组。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="114">firstChild</td><td valign="top" width="596">以Node的形式返回当前节点的第一个子节点。如果没有子节点，则为null。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="114">lastChild</td><td valign="top" width="596">以Node的形式返回当前节点的最后一个子节点。如果没有子节点，则为null。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="114">nextSibling</td><td valign="top" width="596">以Node的形式返回当前节点的兄弟下一个节点。如果没有这样的节点，则返回null。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="114">nodeName</td><td valign="top" width="596">节点的名字，Element节点则代表Element的标记名称。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="114">nodeType</td><td valign="top" width="596">代表节点的类型。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="114">parentNode</td><td valign="top" width="596">以Node的形式返回当前节点的父节点。如果没有父节点，则为null。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="114">previousSibling</td><td valign="top" width="596">以Node的形式返回紧挨当前节点、位于它之前的兄弟节点。如果没有这样的节点，则返回null。</td></tr></tbody></table><p>　　Node对象常用方法：</p><p></p><table cellspacing="1" cellpadding="4" bgcolor="#000000"><tbody><tr bgcolor="#ffffff"><td valign="top" width="144">方法</td><td valign="top" width="566">描述</td></tr><tr bgcolor="#ffffff"><td valign="top" width="144">appendChild()</td><td valign="top" width="566">通过把一个节点增加到当前节点的childNodes[]组，给文档树增加节点。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="144">cloneNode()</td><td valign="top" width="566">复制当前节点，或者复制当前节点以及它的所有子孙节点。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="144">hasChildNodes()</td><td valign="top" width="566">如果当前节点拥有子节点，则将返回true。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="144">insertBefore()</td><td valign="top" width="566">给文档树插入一个节点，位置在当前节点的指定子节点之前。如果该节点已经存在，则删除之再插入到它的位置。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="144">removeChild()</td><td valign="top" width="566">从文档树中删除并返回指定的子节点。</td></tr><tr bgcolor="#ffffff"><td valign="top" width="144">replaceChild()</td><td valign="top" width="566">从文档树中删除并返回指定的子节点，用另一个节点替换它。</td></tr></tbody></table><p>　　接下来，让我们使用上述的DOM应用编程接口，来试着操作HTML文档。</p><p>　　<strong>A、遍历文档的节点</strong></p><p>　　DOM把一个HTML文档视为树，因此，遍历整个树是应该是家常便饭。跟之前说过的一样，这里我们提供两个遍历树的例子。通过它，我们能够学会如何使用childNodes[]和firstChile、lastChild、nextSibling、previousSibling遍历整棵树。</p><p>　　<strong>例子1-- sample3_1.htm：<br /></strong>　　这个例子使用了childNodes[]和递归方式来遍历整个文档，统计文档中出现的Element元素总数，并把Element标记名全部打印出来。需要特别注意的是，在使用DOM时，必须等文档被装载完毕再执行遍历等行为操作文档。sample3_1.htm具体代码如下：</p><pre class="precode">&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=gb2312"&gt;
&lt;title&gt;无标题文档&lt;/title&gt;
&lt;script language="javascript"&gt;
var elementName = ""; //全局变量，保存Element标记名，使用完毕要清空
function countTotalElement(node) { //参数node是一个Node对象
	var total = 0;
	if(node.nodeType == 1) { //检查node是否为Element对象
		total++;			//如果是，计数器加1
		elementName = elementName + node.tagName + "\r\n"; //保存标记名
	}
	var childrens = node.childNodes;		//获取node的全部子节点
	for(var i=0;i&lt;childrens.length;i++) {
		total += countTotalElement(childrens[i]); //在每个子节点上进行递归操作
	}
	return total;
}
&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;a href="javascript:void(0)" 
onClick="alert('标记总数：' + countTotalElement(document) + '\r\n<br /><br />全部标记如下：\r\n' + elementName);elementName='';"&gt;开始统计&lt;/a&gt;
&lt;/body&gt;
&lt;/html&gt;</pre><p align="center"><img src="http://dev2dev.bea.com.cn/images/image0511140032.jpg" /><img src="http://dev2dev.bea.com.cn/images/image0511140042.jpg" /></p><p>　　<strong>例子2 – sample3_2.htm：<br /></strong>　　接下来使用firstChile、lastChild、nextSibling、previousSibling遍历整个文档树。修改一下countTotalElement函数，其他跟sample3_1.htm一样：</p><pre class="precode">function countTotalElement(node) { //参数node是一个Node对象
	var total = 0;
	if(node.nodeType == 1) { //检查node是否为Element对象
		total++;			//如果是，计数器加1
		elementName = elementName + node.tagName + "\r\n"; //保存标记名
	}
	var childrens = node.childNodes;		//获取node的全部子节点
	for(var m=node.firstChild; m!=null;m=m.nextSibling) {
		total += countTotalElement(m); //在每个子节点上进行递归操作
	}
	return total;
}
</pre><p>　　<strong>B、搜索文档中特定的元素<br /></strong>　　在使用DOM的过程中，有时候需要定位到文档中的某个特定节点，或者具有特定类型的节点列表。这种情况下，可以调用Document对象的getElementsByTagName()和getElementById()方法来实现。</p><p>　　document.getElementsByTagName()返回文档中具有指定标记名的全部Element节点数组（也是NodeList类型）。Element出现在数组中的顺序就是他们在文档中出现的顺序。传递给getElementsByTagName()的参数忽略大小写。比如，想定位到第一个&lt;table&gt;标记，可以这样写：document.getElementsByTagName(“table”)[0]。例外的，可以使用document.body定位到&lt;body&gt;标记，因为它是唯一的。</p><p>　　getElementsByTagName()返回的数组取决于文档。一旦文档改变，返回结果也立即改变。相比，getElementById()则比较灵活，可以随时定位到目标，只是要实现给目标元素一个唯一的id属性值。这个我们在《AJAX开发简略》的“级联菜单”例子中已经使用过了。</p><p>　　Element对象也支持getElementsByTagName()和getElementById()。不同的是，搜索领域只针对调用者的子节点。</p><p>　　<strong>C、修改文档内容<br /></strong>　　遍历整棵文档树、搜索特定的节点，我们最终目的之一是要修改文档内容。接下来的三个例子将使用Node的几个常用方法，来演示如何修改文档内容。</p><p>　　<strong>例子3 -- sample4_1.htm：<br /></strong>　　这个例子包含三个文本节点和一个按钮。点击按钮后，三个文本节点和按钮的顺序将被颠倒。程序使用了Node的appendChild()和removeChild()方法。</p><pre class="precode">&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=gb2312"&gt;
&lt;title&gt;无标题文档&lt;/title&gt;
&lt;script language="javascript"&gt;
	function reverseNode(node) { // 颠倒节点node的顺序
		var kids = node.childNodes; //获取子节点列表
		var kidsNum = kids.length; //统计子节点总数
		for(var i=kidsNum-1;i&gt;=0;i--) { //逆向遍历子节点列表
			var c = node.removeChild(kids[i]); //删除指定子节点，保存在c中
			node.appendChild(c); //将c放在新位置上
		}
	}
&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p&gt;第一行&lt;/p&gt;
&lt;p&gt;第二行&lt;/p&gt;
&lt;p&gt;第三行&lt;/p&gt;
&lt;p&gt;&lt;input type="button" name="reverseGo" value="颠倒" 
onClick="reverseNode(document.body)"&gt;&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre><p align="center"><img src="http://dev2dev.bea.com.cn/images/image051114007.jpg" /><img src="http://dev2dev.bea.com.cn/images/image051114008.jpg" /></p><p>　　<strong>例子4-- sample4_2.htm：<br /></strong>　　例子1通过直接操作body的子节点来修改文档。在HTML文档中，布局和定位常常通过表格&lt;table&gt;来实现。因此，例子4将演示操作表格内容，将表格的四个单元行顺序颠倒。如果没有使用&lt;tbody&gt;标签，则&lt;table&gt;把全部的&lt;tr&gt;当做是属于一个子节点&lt;tbody&gt;，所以我们采用数组缓存的方式，把行数据颠倒一下。这个例子同时也演示了如何使用DOM创建表格单元行。</p><pre class="precode">&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=gb2312"&gt;
&lt;title&gt;无标题文档&lt;/title&gt;
&lt;script language="javascript"&gt;
function reverseTable() {
	var node = document.getElementsByTagName("table")[0]; //第一个表格
	var child = node.getElementsByTagName("tr"); //取得表格内的所有行
	var newChild = new Array(); //定义缓存数组，保存行内容
	for(var i=0;i&lt;child.length;i++) {
		newChild[i] = child[i].firstChild.innerHTML; 
	}
	node.removeChild(node.childNodes[0]); //删除全部单元行
	var header = node.createTHead(); //新建表格行头
	for(var i=0;i&lt;newChild.length;i++) {
		var headerrow = header.insertRow(i); //插入一个单元行
		var cell = headerrow.insertCell(0); //在单元行中插入一个单元格
		//在单元格中创建TextNode节点
		cell.appendChild(document.createTextNode(newChild[newChild.length-i-1]));
	}
}
&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;table width="200" border="1" cellpadding="4" cellspacing="0"&gt;
    &lt;tr&gt;
        &lt;td height="25"&gt;第一行&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td height="25"&gt;第二行&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td height="25"&gt;第三行&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td height="25"&gt;第四行&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;
&lt;br&gt;
&lt;input type="button" name="reverse" value="开始颠倒" onClick="reverseTable()"&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre><p align="center"><img src="http://dev2dev.bea.com.cn/images/image051114011.jpg" /><img src="http://dev2dev.bea.com.cn/images/image051114012.jpg" /></p><p>　　<strong>例子5 -- sample4_3.htm：<br /></strong>　　正如我们在Node节点介绍部分所指出的那样，appendChild()、replaceChild()、removeChild()、insertBefore()方法会立即改变文档的结构。下面的例子包含两个表格，我们试着把表格二的内容替换表格一的内容。</p><pre class="precode">&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=gb2312"&gt;
&lt;title&gt;无标题文档&lt;/title&gt;
&lt;script language="javascript"&gt;
function replaceContent() {
	var table1 = document.getElementsByTagName("table")[0];
	var table2 = document.getElementsByTagName("table")[1];
	var kid1 = table1.firstChild.firstChild.firstChild; //定位到&lt;td&gt;节点
	var kid2 = table2.firstChild.firstChild.firstChild; //定位到&lt;td&gt;节点
	var repKid = kid2.firstChild; //定位到表格二&lt;td&gt;内含的TextNode节点
	try {
		//用表格二的单元格内容替换表格一的单元格内容，表格二变成没有单元格内容
		kid1.replaceChild(repKid,kid1.firstChild); 
		//下面注释如果开放，将出现object error，因为表格二已经被改变
		//kid2.replaceChild(kid1.firstChild,kid2.firstChild);
	}catch(e){
		alert(e);
	}
}
&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;table width="200" border="1" cellspacing="0" cellpadding="0"&gt;
&lt;tbody&gt;
    &lt;tr&gt;
        &lt;td&gt;表格一&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;br&gt;
&lt;table width="200" border="1" cellspacing="0" cellpadding="0"&gt;
&lt;tbody&gt;
    &lt;tr&gt;
        &lt;td&gt;表格二&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;br&gt;
&lt;input type="button" name="replaceNode" value="替换" onClick="replaceContent()"&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre><p align="center"><img src="http://dev2dev.bea.com.cn/images/image051114015.jpg" /><img src="http://dev2dev.bea.com.cn/images/image051114016_0000.jpg" /></p><p>　　注意，当执行kid1.replaceChild(repKid,kid1.firstChild);的时候，table2的子节点已经被转移到table1了，table2已经没有子节点，不能再调用table2的子节点。看看代码的注释，试着运行一下，应该就知道文档是怎么改变的了。</p><p>　　<strong>D、往文档添加新内容<br /></strong>　　在学会遍历、搜索、修改文档之后，我们现在试着网文档添加新的内容。其实没有什么新意，只是利用我们上述提到的Node的属性和方法而已，还是操作&lt;table&gt;标记的内容。有新意的是，我们要实现一个留言簿。是的，留言簿，你可以往里面留言，只是不能刷新噢。</p><p>　　<strong>例子6 – sample5_1.htm：</strong></p><pre class="precode">&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=gb2312"&gt;
&lt;title&gt;无标题文档&lt;/title&gt;
&lt;script language="javascript"&gt;
function insertStr() {
	var f = document.form1;
	var value = f.str.value;
	if(value!="") {
		// 从最终的TextNode节点开始，慢慢形成&lt;tbody&gt;结构
		var text = document.createTextNode(value); //新建一个TextNode节点
		var td = document.createElement("td"); //新建一个td类型的Element节点
		var tr = document.createElement("tr"); //新建一个tr类型的Element节点
		var tbody = document.createElement("tbody"); //新建一个tbody类型的Element节点
		td.appendChild(text); //将节点text加入td中
		tr.appendChild(td); //将节点td加入tr中
		tbody.appendChild(tr); //将节点tr加入tbody中
		var parNode = document.getElementById("table1"); //定位到table上
		parNode.insertBefore(tbody,parNode.firstChild); //将节点tbody插入到节点顶部
		//parNode.appendChild(tbody); //将节点tbody加入节点尾部
	}
}
&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;form name="form1" method="post" action=""&gt;
    &lt;input name="str" type="text" id="str" value=""&gt;
    &lt;input name="insert" type="button" id="insert" value="留言" onClick="insertStr()"&gt;
&lt;/form&gt;
&lt;table width="400" border="1" cellspacing="0" cellpadding="0" id="table1"&gt;
&lt;tbody&gt;
    &lt;tr&gt;
        &lt;td height="25"&gt;网友留言列表：&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre><p>　　我们之前说过，&lt;table&gt;的子节点是&lt;tbody&gt;，&lt;tbody&gt;的子节点才是&lt;tr&gt;，&lt;tr&gt;是&lt;td&gt;的父节点，最后&lt;td&gt;内部的TextNode节点。所以，往&lt;table&gt;增加单元格行要逐级形成，就像往树里面添加一个枝桠一样，要有叶子有径。看看，这个留言簿是不是很简单啊。这个例子同时也演示了往&lt;table&gt;表格标记里面增加内容的另一种方法。</p><p align="center"><img src="http://dev2dev.bea.com.cn/images/image051114019.jpg" /><br /><img src="http://dev2dev.bea.com.cn/images/image051114020.jpg" /></p><p>　　<strong>E、使用DOM操作XML文档<br /></strong>　　在数据表示方面，XML文档更加结构化。DOM在支持HTML的基础上提供了一系列的API，支持针对XML的访问和操作。利用这些API，我们可以从XML中提取信息，动态的创建这些信息的HTML呈现文档。处理XML文档，通常遵循“加载XML文档à提取信息à加工信息à创建HTML文档”的过程。下面的例子演示了如何加载并处理XML文档。</p><p>　　这个例子包含两个JS函数。loadXML()负责加载XML文档，其中既包含加载XML文档的2级DOM代码，又有实现同样操作的Microsoft专有API代码。需要提醒注意的是，文档加载过程不是瞬间完成的，所以对loadXML()的调用将在加载文档完成之前返回。因此，需要传递给loadXML()一个引用，以便文档加载完成后调用。</p><p>　　例子中的另外一个函数makeTable()，则在XML文档加载完毕之后，使用最后前介绍过的DOM应用编程接口读取XML文档信息，并利用这些信息形成一个新的table表格。</p><p>　　<strong>例子7 -- sample6_1.htm：</strong></p><pre class="precode">&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=gb2312"&gt;
&lt;title&gt;无标题文档&lt;/title&gt;
&lt;script language="javascript"&gt;
function loadXML(handler) {
	var url = "employees.xml";
	if(document.implementation&amp;&amp;document.implementation.createDocument) {
		var xmldoc = document.implementation.createDocument("", "", null);
		xmldoc.onload =  handler(xmldoc, url);
		xmldoc.load(url);
	}
	else if(window.ActiveXObject) {
		var xmldoc = new ActiveXObject("Microsoft.XMLDOM");
		xmldoc.onreadystatechange = function() {
			if(xmldoc.readyState == 4) handler(xmldoc, url);
		}
		xmldoc.load(url);
	}
}
function makeTable(xmldoc, url) {
	var table = document.createElement("table");
	table.setAttribute("border","1");
	table.setAttribute("width","600");
	table.setAttribute("class","tab-content");
	document.body.appendChild(table);
	var caption = "Employee Data from " + url;
	table.createCaption().appendChild(document.createTextNode(caption));
	var header = table.createTHead();
	var headerrow = header.insertRow(0);
	headerrow.insertCell(0).appendChild(document.createTextNode("姓名"));
	headerrow.insertCell(1).appendChild(document.createTextNode("职业"));
	headerrow.insertCell(2).appendChild(document.createTextNode("工资"));
	var employees = xmldoc.getElementsByTagName("employee");
	for(var i=0;i&lt;employees.length;i++) {
		var e = employees[i];
		var name = e.getAttribute("name");
		var job = e.getElementsByTagName("job")[0].firstChild.data;
		var salary = e.getElementsByTagName("salary")[0].firstChild.data;
		var row = table.insertRow(i+1);
		row.insertCell(0).appendChild(document.createTextNode(name));
		row.insertCell(1).appendChild(document.createTextNode(job));
		row.insertCell(2).appendChild(document.createTextNode(salary));
	}
}
&lt;/script&gt;
&lt;link href="css/style.css" rel="stylesheet" type="text/css"&gt;
&lt;/head&gt;

&lt;body onLoad="loadXML(makeTable)"&gt;
&lt;/body&gt;
&lt;/html&gt;<br /><strong>供读取调用的XML文档 – employees.xml：</strong><br />
&lt;?xml version="1.0" encoding="gb2312"?&gt;
&lt;employees&gt;
	&lt;employee name="J.Doe"&gt;
		&lt;job&gt;Programmer&lt;/job&gt;
		&lt;salary&gt;32768&lt;/salary&gt;
	&lt;/employee&gt;
	&lt;employee name="A.Baker"&gt;
		&lt;job&gt;Sales&lt;/job&gt;
		&lt;salary&gt;70000&lt;/salary&gt;
	&lt;/employee&gt;
	&lt;employee name="Big Cheese"&gt;
		&lt;job&gt;CEO&lt;/job&gt;
		&lt;salary&gt;100000&lt;/salary&gt;
	&lt;/employee&gt;
&lt;/employees&gt;
</pre><p><a name="a75"></a><strong>7.5、处理XML文档</strong><br />　　脱离XML文档的AJAX是不完整的。在本部分未完成之前，有读者说AJAX改名叫AJAH（H应该代表HTML吧）比较合适。应该承认，XML文档在数据的结构化表示以及接口对接上有先天的优势，但也不是所有的数据都应该用XML表示。有些时候单纯的文本表示可能会更合适。下面先举个AJAX处理返回XML文档的例子再讨论什么时候使用XML。<br /><br />7.5.1、处理返回的XML<br />　　 <strong>例子8 -- sample7_1.htm：<br /></strong>　　在这个例子中，我们采用之前确定的AJAX开发框架，稍微修改一下body内容和processRequest的相应方式，将先前的employees.xml的内容读取出来并显示。 </p><p>　　body的内容如下：</p><pre class="precode">&lt;input type="button" name="read"
 value="读取XML" onClick="send_request('employees.xml')"&gt;
processRequest()方法修改如下：
	// 处理返回信息的函数
    function processRequest() {
        if (http_request.readyState == 4) { // 判断对象状态
            if (http_request.status == 200) { // 信息已经成功返回，开始处理信息
		var returnObj = http_request.responseXML;
		var xmlobj = http_request.responseXML;
		var employees = xmlobj.getElementsByTagName("employee");
		var feedbackStr = "";
		for(var i=0;i&lt;employees.length;i++) { // 循环读取employees.xml的内容
		var employee = employees[i];
		feedbackStr += "员工：" + employee.getAttribute("name");
		feedbackStr += 
" 职位：" + employee.getElementsByTagName("job")[0].firstChild.data;
		feedbackStr +=
 " 工资：" + employee.getElementsByTagName("salary")[0].firstChild.data;
		feedbackStr +=  "\r\n";
				}
				alert(feedbackStr);
            } else { //页面不正常
                alert("您所请求的页面有异常。");
            }
        }
}
</pre><p>　　运行一下，看来效果还不错：</p><p align="center"><img src="http://dev2dev.bea.com.cn/images/image051114028.jpg" /></p><p><a name="_Toc119127385"></a>7.5.2、选择合适的XML生成方式 </p><p>　　现在的web应用程序往往采用了MVC三层剥离的设计方式。XML作为一种数据保存、呈现、交互的文档，其数据往往是动态生成的，通常由JavaBean转换过来。由JavaBean转换成XML文档的方式有好几种，选择合适的转换方式往往能达到事半功倍的效果。下面介绍两种常用的方式，以便需要的时候根据情况取舍。</p><p>　　<strong>A、类自行序列化成XML<br /></strong>　　类自行序列化成XML即每个类都实现自己的toXML()方法，选择合适的API、适当的XML结构、尽量便捷的生成逻辑快速生成相应的XML文档。显然，这种方式必须要求每个类编写专门的XML生成代码，每个类只能调用自己的toXML()方法。应用诸如JDOM等一些现成的API，可以减少不少开发投入。例子9是一个利用JDOM的API形成的toXML()<strong>方法。</strong></p><p>　　<strong>例子9 -- toXml() 的 JDOM 实现 -- Employ类的toXml()方法：</strong></p><pre class="precode">public Element toXml() {  
	Element employee = new Element(“employee”);
	Employee.setAttribute(“name”,name);
	Element jobE = new Element(“job”).addContent(job);
	employee.setContent(jobE);
	Element salaryE = new Element(“salary”).addContent(salary);
	employee.setContent(salaryE);
	return employee;
}
</pre><p>　　JDOM提供了现成的API，使得序列化成XML的工作更加简单，我们只需要把toXML()外面包装一个Document，然后使用XMLOutputter把文档写入servlet就可以了。toXml()允许递归调用其子类的toXML()方法，以便生成包含子图的XML文档。</p><p>　　使用类自行序列化成XML的方式，要每个类都实现自己的toXML()方法，而且存在数据模型与视图耦合的问题，即要么为每个可能的视图编写独立的toXML()方法，要么心甘情愿接收冗余的数据，一旦数据结构或者文档发生改变，toXML()就要做必要的修改。</p><p>　　<strong>B、页面模板生成XML方式<br /></strong>　　一般的，可以采用通用的页面模板技术来生成XML文档，这个XML文档可以符合任何需要的数据模型，供AJAX灵活的调用。另外，模板可以采用任何标记语言编写，提高工作效率。下面是一个采用Struts标签库编写的XML文档，输出之前提到的employees.xml：</p><p>　　<strong>Sample8_2.jsp：</strong></p><pre class="precode">&lt;%@ page contentType="application/xml; charset=gb2312" import="Employee"%&gt;
&lt;%@ page import="java.util.Collection,java.util.ArrayList"%&gt;
&lt;?xml version="1.0"?&gt;
&lt;%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %&gt;
&lt;%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%&gt;
&lt;%
Employee em1 = new Employee();
em1.setName("J.Doe");
em1.setJob("Programmer");
em1.setSalary("32768");
Employee em2 = new Employee();
em2.setName("A.Baker");
em2.setJob("Sales");
em2.setSalary("70000");
Employee em3 = new Employee();
em3.setName("Big Cheese");
em3.setJob("CEO");
em3.setSalary("100000");
Collection employees = new ArrayList();
employees.add(em1);
employees.add(em2);
employees.add(em3);
pageContext.setAttribute("employees",employees);
%&gt;
&lt;employees&gt;
&lt;logic:iterate name="employees" id="employee"&gt;
	&lt;employee name="&lt;bean:write name='employee' property='name'/&gt;"&gt;
		&lt;job&gt;&lt;bean:write name="employee" property="job"/&gt;&lt;/job&gt;
		&lt;salary&gt;&lt;bean:write name="employee" property="salary"/&gt;&lt;/salary&gt;
	&lt;/employee&gt;
&lt;/logic:iterate&gt;
&lt;/employees&gt;
</pre><p>　　<img src="http://dev2dev.bea.com.cn/images/image051114031.jpg" /></p><p>　　采用页面模板生成XML方式，需要为每个需要的的数据模型建立一个对立的JSP文件，用来生成符合规范的XML文档，而不能仅仅在类的toXML()方法中组织对象图来实现。不过，倒是可以更加方便的确保标记匹配、元素和属性的顺序正确以及XML实体正确转义。</p><p>　　参考资料中Philip McCarthy的文章还描述了一种Javascript对象标注的生成方式，本文在此不赘述。有兴趣的读者可以自行查看了解。</p><p><a></a>7.5.3、如何在使用XML还是普通文本间权衡<br />　　使用XML文档确实有其方便之处。不过XML文档的某些问题倒是要考虑一下，比如说延迟，即服务器不能立即解析XML文档成为DOM模型。这个问题在一定程度上会影响AJAX要求的快速反应能力。另外，某些情况下我们并不需要使用XML来表示数据，比如说数据足够简单成只有一个字符串而已。就好像我们之前提到的数据校验和级联菜单的例子一样。所以，个人认为在下面这些情况下可以考虑使用XML来作为数据表示的介质： </p><ul><li>数据比较复杂，需要用XML的结构化方式来表示 
</li><li>不用考虑带宽和处理效率支出 
</li><li>与系统其他API或者其他系统交互，作为一种数据中转中介 
</li><li>需要特定各式的输出视图而文本无法表示的 </li></ul><p>　　总之，要认真评估两种表示方式的表示成本和效率，选择合适的合理的表示方式。　　 </p><p>　　在关于AJAX的系列文章的下一篇，我们将综合使用DOM和XML，来实现一个可以持久化的简单留言簿。另外，还将试着模拟MSN Space的部分功能，来体会AJAX的魅力。<a name="a8"></a></p><p><a><strong>参考文章：</strong></a><br /><br /></p><table cellspacing="1" cellpadding="4" bgcolor="#000000"><tbody><tr bgcolor="#ffffff"><td valign="top" width="69">作者：</td><td valign="top" width="150">fanscial</td><td valign="top" width="75">标题：</td><td valign="top" width="416">《AJAX简介》</td></tr><tr bgcolor="#ffffff"><td valign="top" width="69">网址：</td><td valign="top" width="641" colspan="3"><a href="/fanscial/archive/2005/08/31/11628.html" target="_blank"><font color="#0000ff">http://www.blogjava.net/fanscial/archive/2005/08/31/11628.html</font></a></td></tr><tr bgcolor="#ffffff"><td valign="top" width="69">作者：</td><td valign="top" width="150">Amour GUO</td><td valign="top" width="75">标题：</td><td valign="top" width="416">《AJAX内部交流文档》</td></tr><tr bgcolor="#ffffff"><td valign="top" width="69">网址：</td><td valign="top" width="641" colspan="3"><a href="http://www.dragonson.com/doc/ajax.html" target="_blank"><font color="#0000ff">http://www.dragonson.com/doc/ajax.html</font></a></td></tr><tr bgcolor="#ffffff"><td valign="top" width="69">作者：</td><td valign="top" width="150">MoztwWiki</td><td valign="top" width="75">标题：</td><td valign="top" width="416">《AJAX上手篇》</td></tr><tr bgcolor="#ffffff"><td valign="top" width="69">网址：</td><td valign="top" width="641" colspan="3"><a href="http://wiki.moztw.org/index.php/AJAX_%E4%B8%8A%E6%89%8B%E7%AF%87" target="_blank"><font color="#800080">http://wiki.moztw.org/index.php/AJAX_%E4%B8%8A%E6%89%8B%E7%AF%87</font></a></td></tr><tr bgcolor="#ffffff"><td valign="top" width="69">作者：</td><td valign="top" width="150">Philip McCarthy</td><td valign="top" width="75">标题：</td><td valign="top" width="416">面向Java开发人员的Ajax:构建动态的Java应用程序</td></tr><tr bgcolor="#ffffff"><td valign="top" width="69">网址：</td><td valign="top" width="641" colspan="3"><a href="http://kb.csdn.net/java/Articles/200510/bed0423e-5297-49c9-9464-0e3eb733c8b5.html" target="_blank"><font color="#0000ff">http://kb.csdn.net/java/Articles/200510/bed0423e-5297-49c9-9464-0e3eb733c8b5.html</font></a></td></tr><tr bgcolor="#ffffff"><td valign="top" width="69">作者：</td><td valign="top" width="150">Philip McCarthy</td><td valign="top" width="75">标题：</td><td valign="top" width="416">面向Java开发人员的Ajax:Ajax的Java对象序列化</td></tr><tr bgcolor="#ffffff"><td valign="top" width="69">网址：</td><td valign="top" width="641" colspan="3"><a href="http://kb.csdn.net/java/Articles/200510/a5b630cf-a2c2-46f1-8e3b-eadde723e734.html" target="_blank"><font color="#0000ff">http://kb.csdn.net/java/Articles/200510/a5b630cf-a2c2-46f1-8e3b-eadde723e734.html</font></a></td></tr><tr bgcolor="#ffffff"><td valign="top" width="69">作者：</td><td valign="top" width="150">David Flanagan</td><td valign="top" width="75">书名：</td><td valign="top" width="416">《Javascript权威指南》</td></tr></tbody></table><p>　　<strong>OpenDoc版权说明：</strong><br />　　本文档版权归原作者所有。<br />　　在免费、且无任何附加条件的前提下，可在<strong>网络媒体中</strong>自由传播。<br />　　如需部分或者全文引用，请事先征求作者意见。<br />　　如果本文对您有些许帮助，表达谢意的最好方式，是将您发现的问题和文档改进意见及时反馈给作者。当然，倘若有时间和能力，能为技术群体无偿贡献自己的所学为最好的回馈。</p><p align="left">参与讨论：<a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=121&amp;threadID=28135&amp;start=0&amp;tstart=0" target="_blank"><font color="#0000ff">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=121&amp;threadID=28135&amp;start=0&amp;tstart=0</font></a></p><!--文章其他信息--><div class="dot001"><font color="#0000ff"><img height="1" alt="" src="http://dev2dev.bea.com.cn/images/_.gif" width="100%" /></font></div><p></p><table cellspacing="0" cellpadding="3" width="100%" border="0"><tbody><tr valign="bottom"><td colspan="2" height="20"> <span class="h2b">作者简介</span></td></tr><tr><td valign="top" align="middle" width="0"></td><td>dev2dev ID: educhina, 软件工程师，联络方式<a href="mailto:eamoi@163.com"><font color="#0000ff">eamoi@163.com</font></a>（技术） <a href="mailto:zcke0728@hotmail.com"><font color="#0000ff">zcke0728@hotmail.com</font></a>（版权）。 Blog: <a href="/eamoi/" target="_blank"><font color="#0000ff">http://www.blogjava.net/eamoi/</font></a></td></tr></tbody></table><img src ="http://www.blogjava.net/TrampEagle/aggbug/27853.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-01-13 10:01 <a href="http://www.blogjava.net/TrampEagle/articles/27853.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ajax 的Java 对象序列化</title><link>http://www.blogjava.net/TrampEagle/articles/27374.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Tue, 10 Jan 2006 05:31:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/27374.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/27374.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/27374.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/27374.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/27374.html</trackback:ping><description><![CDATA[引自：<A href="http://www.matrix.org.cn/resource/article/43/43910_Java_Ajax.html">http://www.matrix.org.cn/resource/article/43/43910_Java_Ajax.html</A><BR><BR>
<DIV class=title>
<H2>面向Java开发人员的Ajax: Ajax 的Java 对象序列化</H2><A href="http://www.matrix.org.cn/user.shtml;jsessionid=49EB1BDE9C7B1108F95F9A6EE4707908?userid=85240">pawenwen</A> 发表于 2005-10-31<BR>点击数:606 评论数:1 评价:11/3<BR>关键词:ajax </DIV><!-- end of div title -->
<DIV class=summary>
<DIV class=left></DIV>
<DIV class=center>
<H4>摘要:</H4>这篇文章侧重于可以用来生成 Java 对象以数据为中心的视图的技术。我将演示可以把 JavaBeans 变成 XML 文档的各种方法，并且讨论每种方法的优劣。您将看到为什么 XML 并不总是最好的途径：对于简单的 Ajax 请求来说，传输纯文本更好。最后，我将介绍 JavaScript 对象标注（JSON）。JSON 允许数据以序列化的 JavaScript 对象图的形式传输，在客户端代码中处理序列化的 JavaScript 对象图极为容易。 </DIV>
<DIV class=right>
<DIV class=help>
<H4>文章工具</H4><A href="http://www.matrix.org.cn/favorite.shtml;jsessionid=49EB1BDE9C7B1108F95F9A6EE4707908?type=article&amp;title=%25E9%259D%25A2%25E5%2590%2591Java%25E5%25BC%2580%25E5%258F%2591%25E4%25BA%25BA%25E5%2591%2598%25E7%259A%2584Ajax%253A%2BAjax%2B%25E7%259A%2584Java%2B%25E5%25AF%25B9%25E8%25B1%25A1%25E5%25BA%258F%25E5%2588%2597%25E5%258C%2596&amp;url=resource%2Farticle%2F43%2F43910_Java_Ajax.html">收藏</A><BR><A href="http://www.matrix.org.cn/resource/article/43/43910_Java_Ajax.html#avote">投票评分</A><BR><A href="http://www.matrix.org.cn/resource/article/43/43910_Java_Ajax.html#areview">发表评论</A><BR><A onclick="copyLink('面向Java开发人员的Ajax: Ajax 的Java 对象序列化');" href="http://www.matrix.org.cn/resource/article/43/43910_Java_Ajax.html#">复制链接</A><BR></DIV></DIV></DIV><!-- end of summary line -->
<DIV class=overflow id=text>
<CENTER><B><SPAN style="FONT-SIZE: 20px">面向 Java 开发人员的 Ajax: Ajax 的 Java 对象序列化</SPAN></B></CENTER><BR>
<CENTER>在 Ajax 应用程序中序列化数据的五种途径</CENTER><BR>
<CENTER>Philip McCarthy , 软件开发顾问, 独立顾问</CENTER><BR>
<CENTER>2005 年 10 月 24 日</CENTER><BR><BR>如果您正在使用异步 JavaScript 和 XML（Ajax）进行 Java? Web 开发，那么您最关心的问题可能就是把数据从服务器传递给客户机。在 面向 Java 开发人员的 Ajax 系列的第二篇文章中，Philip McCarthy 介绍了 Java 对象序列化的五种方式，并提供了选择最适合应用程序的数据格式和技术所需要的全部信息。<BR>在这个系列的 第一篇文章 中，我介绍了 Ajax 的构造块：<BR><BR>如何用 JavaScript XMLHttpRequest 对象从 Web 页面向服务器发送异步请求。<BR>如何用 Java servlet 处理和响应请求（向客户机返回 XML 文档）。<BR>如何在客户端用响应文档更新页面视图。<BR>这一次，我将继续讨论 Ajax 开发的基础知识，但是将侧重于许多 Java Web 开发人员最关心的问题：为客户机生成数据。<BR><BR>多数 Java 开发人员已经把模型-视图-控制器（MVC）模式应用在他们的 Web 应用程序上。在传统的 Web 应用程序中，视图组件由 JSP 或者其他表示技术（例如 Velocity 模板）构成。这些表示组件动态地生成全新的 HTML 页面，替代用户以前正在查看的页面，从而更新用户界面。但是，在 Java Web 应用程序使用 Ajax UI 的情况下，基于从 XMLHttpRequest 的响应接收到的数据，JavaScript 客户端代码对于更新用户看到的内容负有最终责任。从服务器的角度来看，视图成为它响应客户机请求而发送的数据表示。<BR><BR>这篇文章侧重于可以用来生成 Java 对象以数据为中心的视图的技术。我将演示可以把 JavaBeans 变成 XML 文档的各种方法，并且讨论每种方法的优劣。您将看到为什么 XML 并不总是最好的途径：对于简单的 Ajax 请求来说，传输纯文本更好。最后，我将介绍 JavaScript 对象标注（JSON）。JSON 允许数据以序列化的 JavaScript 对象图的形式传输，在客户端代码中处理序列化的 JavaScript 对象图极为容易。<BR><BR><B>关于示例</B><BR><BR>我将使用一个示例应用程序和几个用例来演示这里讨论的技术特性和技术。图 1 显示的极为简单的数据模型可以表示示例用例。这个模型代表在线商店中的顾客帐户。顾客拥有以前订单的集合，每个订单包含几个商品。<BR><BR>虽然 XMLHttpRequest 对于发送数据使用的格式没有做任何限制，但是对于多数目的来说，只发送传统的表单数据是适合的，所以我的讨论集中在服务器的响应上。响应也可以有基于文本的格式，但是正如它的名字表示的，XMLHttpRequest 具有内置的处理 XML 响应数据的能力。这使 XML 成为 Ajax 响应的默认选择，所以我们从 XML 格式开始讨论。<BR><BR><BR><B>从 Java 类产生 XML</B><BR><BR>把 Ajax 响应作为 XML 来传递有许多原因：每个支持 Ajax 的浏览器都有导航 XML 文档的方法，也有许多服务器端技术可以处理 XML 数据。通过制定一个方案，描述要交换的文档类型，在 Ajax 客户端和服务器端之间很容易定义合约，而且如果服务器端架构采用面向服务的方式，那么使用 XML 也可以允许非 Ajax 客户机使用您提供的数据。<BR><BR>我将考虑从 Java 对象产生 XML 数据的三种方法，并讨论每种方法的优劣。<BR><BR><BR><B>自行进行序列化</B><BR><BR>首先，可以从对象图以编程的方式生成 XML。这种方式可以简单到只是在每个 JavaBean 类中实现 toXml() 方法即可。然后就可以选择合适的 XML API，让每个 bean 提供表示自己状态的元素，并递归地对自己的成员调用对象图。显然，这种方式无法扩展到大量的类，因为每个类都需要专门编写自己的 XML 生成代码。从好的方面来看，这是一个实现起来简单的方式，没有额外的配置支出或者更复杂的构建过程支出，任何 JavaBean 图都可以只用几个调用就变成 XML 文档。<BR><BR>在本系列 前一篇文章 的示例代码中，我把 XML 标记字符串连接在一起，实现了 toXml() 方法。上次我就提到过，这是个糟糕的方法，因为它把确保标记配对、实体编码等工作的负担放在每个 toXml() 方法的代码中。在 Java 平台上有几个 XML API 可以替您做这些工作，这样您就可以把精力集中在 XML 的内容上。清单 1 用 JDOM API 实现了在线商店示例中表示订单的类中的 toXml()。<BR><BR><BR>清单 1. Order 类的 toXml() 的 JDOM 实现<BR><BR><PRE class=overflow>public Element toXml() {<BR><BR>&nbsp;&nbsp;Element elOrder = new Element("order");<BR>&nbsp;&nbsp;elOrder.setAttribute("id",id);<BR><BR>&nbsp;&nbsp;elOrder.setAttribute("cost",getFormattedCost());<BR><BR>&nbsp;&nbsp;Element elDate = new Element("date").addContent(date);<BR>&nbsp;&nbsp;elOrder.addContent(elDate);<BR><BR>&nbsp;&nbsp;Element elItems = new Element("items");<BR>&nbsp;&nbsp;for (Iterator&lt;Item&gt; iter = <BR>&nbsp;&nbsp; items.iterator() ; iter.hasNext() ; ) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;elItems.addContent(iter.next().toXml());<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;elOrder.addContent(elItems);<BR><BR>&nbsp;&nbsp;return elOrder;<BR>}</PRE><BR><BR><BR>在这里可以看到用 JDOM 创建元素、使用属性和添加元素内容有多么简单。递归地调用复合 JavaBean 的 toXml() 方法是为了取得它们子图的 Element 表示。例如，items 元素的内容是通过调用 Order 聚合的每个 Item 对象上的 toXml() 得到的。<BR><BR>一旦所有的 JavaBean 都实现了 toXml() 方法，那么把任意对象图序列化成 XML 文档并返回给 Ajax 客户机就简单了，如清单 2 所示。<BR><BR><BR>清单 2. 从 JDOM 元素生成 XML 响应<BR><BR><PRE class=overflow>public void doGet(HttpServletRequest req, HttpServletResponse res)<BR>&nbsp;&nbsp;throws java.io.IOException, ServletException {<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;String custId = req.getParameter("username");<BR>&nbsp;&nbsp;&nbsp;&nbsp;Customer customer = getCustomer(custId);<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;Element responseElem = customer.toXml();<BR>&nbsp;&nbsp;&nbsp;&nbsp;Document responseDoc = new Document(responseElem);<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;res.setContentType("application/xml");<BR>&nbsp;&nbsp;&nbsp;&nbsp;new XMLOutputter().output(responseDoc,res.getWriter());<BR>}<BR> </PRE><BR><BR>JDOM 再次把工作变得非常简单。只需要在对象图返回的 XML 元素外面包装一个 Document，然后用 XMLOutputter 把文档写入 servlet 响应即可。清单 3 显示了用这种方式生成的 XML 示例，用 JDOM Format.getPrettyFormat() 对 XMLOutputter 进行初始化，格式化得非常好。在这个示例中，顾客只做了一个订单，包含两个商品。<BR><BR><BR>清单 3. 代表顾客的 XML 文档<BR><BR><PRE class=overflow>&lt;?xml version="1.0" encoding="UTF-8"?&gt;<BR>&lt;customer username="jimmy66"&gt;<BR>&nbsp;&nbsp;&lt;realname&gt;James Hyrax&lt;/realname&gt;<BR>&nbsp;&nbsp;&lt;orders&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;order id="o-11123" cost="$349.98"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;date&gt;08-26-2005&lt;/date&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;items&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;item id="i-55768"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Oolong 512MB CF Card&lt;/name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;description&gt;512 Megabyte Type 1 CompactFlash card. <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Manufactured by Oolong Industries&lt;/description&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;price&gt;$49.99&lt;/price&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/item&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;item id="i-74491"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Fujak Superpix72 Camera&lt;/name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;description&gt;7.2 Megapixel digital camera featuring six <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;shooting modes and 3x optical zoom. Silver.&lt;/description&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;price&gt;$299.99&lt;/price&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/item&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/items&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/order&gt;<BR>&nbsp;&nbsp;&lt;/orders&gt;<BR>&lt;/customer&gt;</PRE><BR><BR><BR><BR><B>自行序列化的不足</B><BR><BR>有趣的是，清单 3 中的代码展示了让 JavaBean 把自己序列化为 XML 的一个主要不足。假设要用这个文档表示顾客的订单历史视图。在这种情况下，不太可能要显示每个历史订单中每个商品的完整说明，或者告诉顾客他或她自己的姓名。但是如果应用程序有一个 ProductSearch 类，它就是以 Item bean 列表的形式返回搜索结果，那么在 Item 的 XML 表示中包含说明可能会有帮助。而且，Item 类上代表当前库存水平的额外字段，在产品搜索视图中可能就是需要显示的有用信息。但是，不管当前的库存水平是否与当前情况相关（比如对顾客的订单历史来说），这个字段都会从包含 Item 的任何对象图中序列化出来。<BR><BR>从设计的角度来看，这是数据模型与视图生成耦合的经典问题。每个 bean 只能用一种途径序列化自己，一成不变的方式意味着 Ajax 交互最终要交换它们不需要交换的数据，因此造成客户端代码要从文档中找到需要的信息更加困难，而且也会增加带宽消耗和客户端的 XML 解析时间。这种耦合的另一个后果就是 XML 的语法不能脱离 Java 类独立变化。例如，对顾客文档的方案做修改，可能会影响多个 Java 类，造成它们也不得不做修改和重新编译。<BR><BR>我稍后会解决这些问题，但是首先来看一个对自行序列化方式的可伸缩性问题的解决方案：XML 绑定框架。<BR><BR><BR><BR><BR><B>XML 绑定框架</B><BR><BR>近些年来，已经开发了多个 Java API 来简化 XML 文档到 Java 对象图的绑定过程。多数都提供了 XML 编排和拆解；也就是说，它们可以在 Java 对象图和 XML 之间执行双向会话。这些框架封装了 XML 处理的全部工作，这意味着应用程序代码只需要处理普通的 Java 类。它们还希望提供有用的辅助功能，例如文档验证。笼统来说，这些框架采用了两种不同的方式：代码生成和对象到 XML 映射。我将分别解释这两种方式。<BR><BR><B>代码生成方式</B><BR><BR>使用代码生成的框架包括 XMLBeans、JAXB、Zeus 和 JBind。Castor 也能使用这项技术。这类框架的起点是描述文档数据类型的 XML 方案。使用框架提供的工具，就可以生成代表这些方案定义类型的 Java 类。最后，用这些生成的类编写应用程序，表示自己的模型数据，并通过框架提供的一些辅助机制把数据序列化成 XML。<BR><BR>如果应用程序要使用大型 XML 语法，那么代码生成方式是个很好的方法。在数十个类上编写定制 XML 序列化代码的可伸缩性问题由此消除。另一方面，也不再需要定义自己的 JavaBean。框架生成的 Java 类通常非常符合 XML 的结构，所以对它们进行编码很难。而且，生成的类变成哑数据容器，因为一般不能向它们添加行为。一般来说，在应用程序代码中要做些妥协，才能很好地处理方案生成的类型。另一个缺陷是如果修改方案，会造成生成的类也要修改，所以也就会对围绕它们编写的代码带来相应的影响。<BR><BR>这种类型的 XML 绑定框架在数据拆解时最有用（例如，使用 XML 文档并把它们转化成 Java 对象）。除非拥有大型数据模型而且有可能从生成的类中获益，否则基于代码生成的框架对于 Ajax 应用程序来说可能有很大的杀伤力。<BR><BR><B>映射方式</B><BR><BR>采用映射方式的框架包括 Castor 和 Apache Commons Betwixt。映射通常是比代码生成更灵活和更轻量的解决方案。首先，可以像通常一样编写 JavaBean，包括任何行为以及任何自己喜欢的方便的方法。然后，在运行时，调用框架中基于内省的编排器，并根据对象成员的类型、名称和值生成 XML 文档。通过定义类的映射文件，可以覆盖默认的绑定策略，并就类在 XML 中的表示方式对编排器提出建议。<BR><BR>这种方法是在可伸缩性与灵活性之间的良好折中。可以按照自己喜欢的方式编写 Java 类，编排器负责处理 XML。虽然映射定义文件编写起来简单，可伸缩性也足够好，但是映射规则最多只能改变标准的绑定行为，而且在对象结构和它们的 XML 表示之间总要残留一些耦合。最终，可能不得不在 Java 表示或 XML 格式之间任选一个做些折中，才能让映射方法起作用。<BR><BR><B>数据绑定总结</B><BR><BR>Dennis Sosnoski 就 XML 数据绑定 API 的主题，在代码生成和代码映射两个方面写了深入的文章。如果想进一步研究这个领域，我推荐他在 Castor 和代码生成框架方面的精彩文章（请参阅 参考资料 中的链接）。<BR><BR>总之，代码生成方式损失了过多的灵活性和方便性，对于典型的 Ajax 应用程序用处不大。另一方面，基于映射的框架可能工作得很好，但是要恰到好处地调整它们的映射策略，以便从对象生成需要的 XML。<BR><BR>所有的 XML 绑定 API 都具有手工序列化技术的一个主要不足：模型和视图的耦合。被限制为一个类型一个 XML 表示，就意味着在网络上总要有冗余数据传输。更严重的问题是，在情况要求客户端代码使用专门视图时，客户端代码却无法得到它，所以可能要费力地处理给定对象图的一成不变的视图。<BR><BR>在传统的 Web 应用程序开发中，采用页面模板系统把视图生成与控制器逻辑和模型数据干净地分离。这种方法在 Ajax 场景中也会有帮助。 <BR><BR><BR><BR><B>页面模板系统</B><BR><BR>任何通用目的的页面模板技术都可以用来生成 XML，从而使 Ajax 应用程序根据自己的数据模型生成任何 XML 响应文档。额外收获是：模板可以用简单的、表现力强的标记语言编写，而不是用一行行的 Java 代码编写。清单 5 是一个 JSP 页面，采用了 Customer bean 并表示出定制的 XML 视图，适合客户端代码生成订单历史组件。<BR><BR><BR>清单 4. 生成订单历史文档的 JSP<BR><BR><PRE class=overflow>&lt;?xml version="1.0"?&gt;<BR>&lt;%@ page contentType="application/xml" %&gt;<BR>&lt;%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %&gt;<BR>&lt;c:set var="cust" value="${requestScope.customer}"/&gt;<BR><BR>&lt;orderhistory username="${cust.username}"&gt;<BR>&lt;c:forEach var="order" items="${cust.orders}"&gt;<BR>&nbsp;&nbsp;&lt;order id="${order.id}" cost="${order.formattedCost}"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;date&gt;${order.date}&lt;/date&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;items&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;c:forEach var="item" items="${order.items}"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;item id="${item.id}"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;&lt;c:out value="${item.name}" escapeXml="true"/&gt;&lt;/name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;price&gt;${item.formattedPrice}&lt;/price&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/item&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/c:forEach&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/items&gt;<BR>&nbsp;&nbsp;&lt;/order&gt;<BR>&lt;/c:forEach&gt;<BR>&lt;/orderhistory&gt;</PRE><BR><BR><BR>这个简洁的模板只输出订单历史视图需要的数据，不输出不相关的资料（例如商品说明）。创建产品搜索视图的定制 XML 应当同样简单，这个视图包含每个商品的完整说明和库存水平。<BR><BR><B>模板的问题</B><BR><BR>另一方面，现在我需要为每个不同视图创建一个新 JSP，而不能仅仅把需要的对象图组织起来并序列化它。从设计的角度来说，许多人可能会有争议，认为这无论如何是件好事，因为这意味着正式地考虑服务器要生成的文档类型。而且，因为我现在要处理通用的模板环境，而不是特定于 XML 的 API，所以确保标记匹配、元素和属性的顺序正确以及 XML 实体（例如 &lt; 或 &amp;）正确转义就成了我的责任。JSP 的核心 out 标记使后面这项工作变得很容易，但是不是所有的模板技术都提供了这样的机制。最后，没有方便的途径可以在服务器端根据方案检验生成的 XML 文档的正确性，但这毕竟不是要在生产环境中做的事，可以方便地在开发期间处理它。 <BR><BR><BR><BR><B>不用 XML 的响应数据</B><BR><BR>迄今为止，我介绍的所有技术都用 XML 文档的形式生成服务器响应。但是，XML 有一些问题。其中一个就是延迟。浏览器不能立即解析 XML 文档并生成 DOM 模型，所以这会降低某些 Ajax 组件需要的“迅捷”感，特别是在较慢的机器上解析大型文档的时候更是如此。“现场搜索”就是一个示例，在这种搜索中，当用户输入搜索术语时，就会从服务器提取搜索结果并显示给用户。对于现场搜索组件来说，迅速地响应输入是非常重要的，但是同时它还需要迅速而持续地解析服务器的响应。<BR><BR>延迟是一个重要的考虑因素，但是避免使用 XML 的最大原因是差劲的客户端 DOM API。清单 5 显示了使用跨浏览器兼容的方式通过 DOM 得到某个值的时候，通常不得不面对的困难。<BR><BR><BR>清单 5. 在 JavaScript 中导航 XML 响应文档<BR><BR><PRE class=overflow>// Find name of first item in customer's last order<BR>var orderHistoryDoc = req.responseXML;<BR><BR>var orders = orderHistoryDoc.getElementsByTagName("order");<BR>var lastOrder = orders[orders.length - 1];<BR><BR>var firstItem = lastOrder.getElementsByTagName("item")[0];<BR>var itemNameElement = firstItem.firstChild;<BR><BR>var itemNameText = itemNameElement.firstChild.data;<BR> </PRE><BR><BR>当元素中间存在空白时，情况就变得更加复杂，因为每个元素的 firstChild 经常是个空白文本节点。现在有 JavaScript 库可以缓解处理 XML 文档的麻烦。这些库包括 Sarissa （请参阅 参考资料）和 Google-ajaXSLT，这两个库都把 XPath 功能添加到了大多数浏览器中。<BR><BR>但是，想想替代方案还是值得的。除了 responseXML 之外，XMLHttpRequest 对象还提供了名为 responseText 的属性，这个属性只是以字符串的方式提供服务器的响应体。<BR><BR><B>responseText 属性</B><BR><BR>当服务器需要向客户机发送非常简单的值时，responseText 特别方便，它可以避免 XML 导致的带宽支出和处理支出。例如，简单的 true/false 响应可以由服务器以纯文本方式返回，可以是逗号分隔的简单的名称或数字列表。但是，一般来说，最好不要在同一个应用程序中把 XML 响应和纯文本响应混合使用；保持单一数据格式可以让代码抽象和重用更加简单。<BR><BR>responseText 与 XML 响应数据结合时也会有用。在只需要从响应文档中提取单一值的场景中，“欺骗性”地把 XML 当作文本字符串，而不把它当作结构化的文档对待，会更方便。例如，清单 6 显示了如何用正则表达式从顾客的订单历史中提取第一笔订单的日期。不过，这实际是种花招，一般不应当依赖 XML 文档的词汇表达。<BR><BR><BR>清单 6. 用正则表达式处理 XMLHttpRequest 的 responseText 对象<BR><BR><PRE class=overflow>var orderHistoryText = req.responseText;<BR>var matches = orderHistoryText.match(/&lt;date&gt;(.*?)&lt;\/date&gt;/);<BR><BR>var date = matches[1];</PRE><BR><BR><BR><BR>在某些情况下，采用即时方式使用 responseText 会比较方便。但是，理想情况下，应当有种途径，可以用一种能够让 JavaScript 轻松导航、却没有 XML 处理支出的格式表示复杂的结构化数据。幸运的是，确实存在这样一种格式。 <BR><BR><BR><BR><B>JavaScript 对象标注</B><BR><BR>实际上，JavaScript 对象的大部分都由联合数组、数字索引数组、字符串、数字或者这些类型的嵌套组合而成。因为所有类型都可以用 JavaScript 直接声明，所以可以在一条语句中静态地定义对象图。清单 7 使用 JSON 语法声明了一个对象，并演示了如何访问这个对象。大括号表示联合数组（即对象），它的键 -值组合由逗号分隔。方括号表示数字索引数组。<BR><BR><BR>清单 7. 用 JSON 在 JavaScript 中直接声明一个简单对象<BR><BR><PRE class=overflow>var band = {<BR>&nbsp;&nbsp;name: "The Beatles",<BR>&nbsp;&nbsp;members: [<BR>&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name: "John",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;instruments: ["Vocals","Guitar","Piano"]<BR>&nbsp;&nbsp;&nbsp;&nbsp;},<BR>&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name: "Paul",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;instruments: ["Vocals","Bass","Piano","Guitar"]<BR>&nbsp;&nbsp;&nbsp;&nbsp;},<BR>&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name: "George",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;instruments: ["Guitar","Vocals"]<BR>&nbsp;&nbsp;&nbsp;&nbsp;},<BR>&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name: "Ringo",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;instruments: ["Drums","Vocals"]<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;]<BR>};<BR><BR>// Interrogate the band object<BR>var musician = band.members[3];<BR>alert( musician.name<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ " played " + musician.instruments[0] <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ " with " + band.name );<BR> </PRE><BR><BR>既然 JSON 是一个有趣的语言特性，那么它对 Ajax 有什么意义呢？妙处在于可以用 JSON 在 Ajax 服务器响应中通过网络发送 JavaScript 对象图。这意味着在客户端可以避免使用笨拙的 DOM API 对 XML 进行导航 —— 只需要分析 JSON 响应，就会立即得到可以访问的 JavaScript 对象图。但是，首先需要把 JavaBean 变成 JSON。<BR><BR><B>从 Java 类产生 JSON</B><BR><BR>不同 XML 生成技术所具有的优缺点也适用于 JSON 的产生。而且可以证明，存在需要再次使用表示模板技术的情况。但是，使用 JSON 在理念上更接近于在应用层之间传递序列化的对象，而不是创建应用程序状态的视图。我将介绍如何用 org.json 这个 Java API 在 Java 类上创建 toJSONObject() 方法。然后，就可以把 JSONObject 简单地序列化成 JSON。清单 8 反映了 清单 1 讨论的 XML，显示了 Order 类的 toJSONObject() 实现。<BR><BR><BR>清单 8. Order 类的 toJSONObject() 方法实现<BR><BR><PRE class=overflow>public JSONObject toJSONObject() {<BR><BR>&nbsp;&nbsp;JSONObject json = new JSONObject();<BR>&nbsp;&nbsp;json.put("id",id);<BR>&nbsp;&nbsp;json.put("cost",getFormattedCost());<BR>&nbsp;&nbsp;json.put("date",date);<BR><BR>&nbsp;&nbsp;JSONArray jsonItems = new JSONArray();<BR>&nbsp;&nbsp;for (Iterator&lt;Item&gt; iter = <BR>&nbsp;&nbsp; items.iterator() ; iter.hasNext() ; ) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;jsonItems.put(iter.next().toJSONObject());<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;json.put("items",jsonItems);<BR><BR>&nbsp;&nbsp;return json;<BR>}</PRE><BR><BR><BR><BR>可以看到，org.json API 非常简单。 JSONObject 代表 JavaScript 对象（即联合数组），有不同的 put() 方法，方法接受的 String 键和值是原生类型、String 类型或其他 JSON 类型。JSONArray 代表索引数组，所以它的 put() 方法只接受一个值。请注意在清单 8 中，创建 jsonItems 数组，然后再用 put() 把它附加到 json 对象上；可以用另外一种方法做这项工作，就是对每个项目调用 json.accumulate("items",iter.next().toJSONObject());。accumulate() 方法与 put() 类似，区别在于它把值添加到按照键进行识别的索引数组。<BR><BR>清单 9 显示了如何序列化 JSONObject 并把它写入 servlet 响应。<BR><BR><BR>清单 9. 从 JSONObject 生成序列化的 JSON 响应<BR><BR><PRE class=overflow>public void doGet(HttpServletRequest req, HttpServletResponse res) <BR>&nbsp;&nbsp;throws java.io.IOException, ServletException {<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String custId = req.getParameter("username");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Customer customer = getCustomer(custId);<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.setContentType("application/x-json");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.getWriter().print(customer.toJSONObject());<BR>}<BR> </PRE><BR><BR><BR>可以看到，它实际上什么也没有做。在这里隐式调用的 JSONObject 的 toString() 方法做了所有工作。请注意，application/x-json 内容类型还有一点不确定 —— 在编写这篇文章的时候，关于 JSON 应当属于什么 MIME 类型还没有定论。但是，目前 application/x-json 是合理的选择。清单 10 显示了这个 servlet 代码的示例响应。<BR><BR><BR>清单 10. Customer bean 的 JSON 表示<BR><BR><PRE class=overflow>{<BR>&nbsp;&nbsp;"orders": [<BR>&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"items": [<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"price": "$49.99",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"description": "512 Megabyte Type 1 CompactFlash card. <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Manufactured by Oolong Industries",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"name": "Oolong 512MB CF Card",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"id": "i-55768"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"price": "$299.99",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"description": "7.2 Megapixel digital camera featuring six <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;shooting modes and 3x optical zoom. Silver.",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"name": "Fujak Superpix72 Camera",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"id": "i-74491"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;],<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"date": "08-26-2005",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"cost": "$349.98",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"id": "o-11123"<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;],<BR>&nbsp;&nbsp;"realname": "James Hyrax",<BR>&nbsp;&nbsp;"username": "jimmy66"<BR>}<BR> </PRE><BR><BR><B>在客户端使用 JSON </B><BR><BR>处理的最后一步是把在客户端把 JSON 数据变成 JavaScript 对象。这可以通过对 eval() 的简单调用实现，这个函数可以即时地解释包含 JavaScript 表达式的字符串。清单 11 把 JSON 响应转变成 JavaScript 对象图，然后执行清单 5 的任务，从顾客的最后一次订单中得到第一个商品的名称。<BR><BR><BR>清单 11. 评估 JSON 响应<BR><BR><PRE class=overflow>var jsonExpression = "(" + req.responseText + ")";<BR>var customer = eval(jsonExpression);<BR><BR>// Find name of first item in customer's last order<BR>var lastOrder = customer.orders[customer.orders.length-1];<BR>var name = lastOrder.items[0].name;</PRE><BR><BR><BR><BR>比较清单 11 和 清单 5 可以发现使用 JSON 的客户端的优势。如果在 Ajax 项目中要在客户端对许多复杂的服务器响应进行导航，那么 JSON 可能适合您的需要。JSON 和 XMLHttpRequest 结合还会让 Ajax 交互看起来更像 RPC 调用而不是 SOA 请求，这对应用程序的设计可能会有意义。在下一篇文章中，我要研究的框架，就是明确地为了让 JavaScript 代码对服务器端对象进行远程方法调用而设计的。<BR><BR><B>JSON 的不足</B><BR><BR>JSON 也有它的不足。使用这里介绍的 JSON 方式，就没有办法针对每个请求对对象的序列化进行裁剪，所以不需要的字段可能经常会在网络上发送。另外，添加 toJSONObject() 方法到每个 JavaBean，可伸缩性不太好，虽然用内省和标注编写一个通用的 JavaBean 到 JSON 的序列化器可能很简单。最后，如果服务器端代码是面向服务的，没有单独针对处理 Ajax 客户请求调整过，那么由于对 XML 一致的支持，XML 会是更好的选择。<BR><BR><BR><B>比较序列化技术</B><BR><BR>现在已经看到了把 Java 状态传输到 Ajax 客户端的五种不同技术。我讨论了自行手工编码 XML 序列化、通过代码生成的 XML 绑定、通过映射机制的 XML 绑定、基于模板的 XML 生成以及手工编码到 JSON 的序列化。每种技术都有自己的优势和不足，分别适用于不同的应用程序架构。 <BR><BR>为了总结每种方式的优势与不足，表 1 从六个方面进行了粗略的评分：<BR><BR>可伸缩性<BR>描述技术适应大量数据类型的容易程度。对于每个附加类型，编码和配置工作量是否会增长？<BR><BR>易于集成<BR>评估把技术集成到项目的简单程度。是否需要更加复杂的构建过程？是否增加了部署的复杂性？<BR><BR>Java 类 API<BR>描述以指定方式处理服务器端 Java 对象的容易程度。是可以编写普通的 bean，还是不得不处理笨拙的文档表示？<BR><BR>对输出的控制<BR>描述对类的序列化表示控制的精确程度。<BR><BR>视图灵活性<BR>评估从同一组对象是否可以创建不同的、定制的数据序列化。<BR><BR>客户端数据访问<BR>描述 JavaScript 代码处理服务器响应数据的难易程度。<BR><BR>表 1. 数据生成技术的相对价值&nbsp;&nbsp;自行编写 XML 通过代码生成的 XML 绑定 通过映射的 XML 绑定 页面模板 XML 手工编码的 JSON 序列化 <BR>可伸缩性 差 好 一般 一般 差 <BR>易于集成 好 差 一般 一般 好 <BR>Java 类 API 好 差 好 好 好 <BR>对输出的控制 好 好 一般 好 好 <BR>视图灵活性 差 差 差 好 差 <BR>客户端数据访问 差 差 差 一般 好 <BR><BR><BR><BR><BR><B>结束语</B><BR><BR>表 1 中的数据并不表明某项序列化技术比其他的技术好。毕竟，六种标准的相对重要性取决于项目的具体情况。例如，如果要处理数百种数据类型，这时想要的是可伸缩性，那么代码生成可能就是最好的选择。如果需要为同一数据模型生成多个不同视图，那么就应当使用页面模板。如果处理的是小规模项目，想降低需要编写的 JavaScript 代码数量，那么请考虑 JSON。<BR><BR>希望这篇文章为您提供了选择适合自己应用程序的序列化技术所需要的信息。请参阅 参考资料 一节，学习关于这里讨论的技术的更多内容。您还应当继续关注这个系列的下一篇文章，在下一篇文章中，我将介绍如何用直接 Web 远程（DWR）编写 Java Ajax 应用程序。DWR 框架支持从 JavaScript 代码中直接调用 Java 类上的方法。换句话说，它替您负责数据序列化的工作，所以您可以在更高的抽象层次上使用 Ajax。<BR></DIV><img src ="http://www.blogjava.net/TrampEagle/aggbug/27374.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-01-10 13:31 <a href="http://www.blogjava.net/TrampEagle/articles/27374.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>