JSON 简介

363922298

贡献于2012-08-26

字数:0 关键词: JSON

摘要 XML——这种用于表示客户端与服务器间数据交换有效负载的格式,几乎已经成了 Web services 的同义词。然而,由于 Ajax 和 REST 技术的出现影响了应用程序架构,这迫使人们开始 寻求`XML 的替代品,如:JavaScript Object Notation(JSON)。 JSON 作为一种更轻、更友好的 Web services 客户端的格式(多采用浏览器的形式或访问 REST 风格 Web 服务的 Ajax 应用程序的形式)引起了 Web 服务供应商的注意。 本文将阐述 JSON 在 Web services 设计中备受推崇的原因,以及它作为 XML 替代方案的主要 优势和局限性。文中还会深入探讨:随着相应的 Web 服务客户端选择使用 JSON,如何才能便捷 地在 Java Web services 中生成 JSON 输出。 XML 的十字路口: 浏览器和 Ajax XML 设计原理已经发布了将近十年。时至今日,这种标记语言已经在广阔的软件应用领域中占 据了主导地位。从 Java、.NET 等主流平台中的配置和部署描述符到应用集成场景中更复杂的应用, XML 与生俱来的语言无关性使之在软件架构师心目中占据着独特的地位。但即便最著名的 XML 权 威也不得不承认:在某些环境中,XML 的使用已经超出了它自身能力的极限。 围绕 Ajax 原理构建的那些 Web 应用程序最能说明 XML 的生存能力,从这一点来看,一种新 的有效负载格式的发展壮大也得益于 XML。这种新的有效负载格式就是 JavaScript Object Notation (JSON)。在探索这种新的标记语言的复杂性之前,首先来分析一下在这种独特的设计形式中,XML 具有哪些局限性。 Ajax 建立了一个用于从远程 Web services 发送和接收数据的独立信道,从而允许 Web 程序执 行信道外(out-of-band)客户端/服务器调用。通俗地说,Ajax 程序中的更新和导航序列在典型的 客户端/服务器环境之外完成,在后台(即信道外)接受到信息后,必须进行一次完整的屏幕刷新。 更多背景信息,请参阅 David Teare 的 Ajax 简介(Dev2Dev)。 这些应用程序更新通常是通过 REST 风格(RESTful)Web services 获得的,一旦被用户的浏 览器接收到,就需要整合到 HTML 页面的总体布局之中,这正是 XML 发挥强大力量的场合。尽管 近年来,脚本语言支持和插件支持已使大多数主流浏览器的功能得到了强化,但许多编程任务依然 难于开展,其中之一就是操纵或处理文本,这通常是使用 DOM 实现的。 采用 DOM 的复杂性源于其基于函数的根,这使得对数据树的简单修改或访问都需要进行无数 次方法调用。此外,众所周知,DOM 在各种浏览器中的实现细节不尽相同,这一过程将带来极为 复杂的编程模式,其跨浏览器兼容性出现问题的可能性极大。接下来的问题显而易见,那就是:如 何使一种标记语言轻松集成到 HTML 页面中以满足 Ajax 的要求? 问题的答案就是:利用所有主流浏览器中的一种通用组件——JavaScript 引擎。XML 需要使用 DOM 之类的机制来访问数据并将数据整合到布局之中,采用这种方法,我们不再使用像 XML 这样 的格式来交付 Ajax 更新,而是采用一种更为简单直观的方式,采用 JavaScript 引擎自然匹配的格 式——也就是 JSON。 既然已经明确了 JSON 与 XML 和 Ajax 之间的关系,下面将进一步探讨 JSON 背后的技术细 节。 JSON 剖析:优点和不足 对于 JSON,首先要明白 JSON 和 XML 一样也是一种简单文本格式。相对于 XML,它更加易 读、更便于肉眼检查。在语法的层面上,JSON 与其他格式的区别是在于分隔数据的字符,JSON 中的分隔符限于单引号、小括号、中括号、大括号、冒号和逗号。下图是一个 JSON 有效负载: {"addressbook": {"name": "Mary Lebow", "address": { "street": "5 Main Street" "city": "San Diego, CA", "zip": 91912, }, "phoneNumbers": [ "619 332-3452", "664 223-4667" ] } } 将上面的 JSON 有效负载用 XML 改写,如下: Mary Lebow
5 Main Street San Diego, CA 619 332-3452 664 223-4667
是不是很相似?但它们并不相同。下面将详细阐述采用 JSON 句法的优点和不足。 优点 乍看上去,使用 JSON 的数据分隔符的优点可能并不那么明显,但存在一个根本性的缘由:它 们简化了数据访问。使用这些数据分隔符时, JavaScript 引擎对数据结构(如字符串、数组、对 象)的内部表示恰好与这些符号相同。 这将开创一条比 DOM 技术更为便捷的数据访问途径。下面列举几个 JavaScript 代码片段来说 明这一过程,这些代码片段会访问先前的 JSON 代码片段中的信息:  访问 JSON 中的名称: addressbook.name  访问 JSON 中的地址: addressbook.address.street  访问 JSON 中的电话号码第一位:addressbook.address.phoneNumbers[0] 如果您具备 DOM 编程经验,就能很快地看出区别;新手可以参看 Document Object Model 的 这一外部资源,这里提供了关于数据导航的实例。 JSON 的另一个优点是它的非冗长性。在 XML 中,打开和关闭标记是必需的,这样才能满足 标记的依从性;而在 JSON 中,所有这些要求只需通过一个简单的括号即可满足。在包含有数以百 计字段的数据交换中,传统的 XML 标记将会延长数据交换时间。目前还没有正式的研究表明 JSON 比 XML 有更高的线上传输效率;人们只是通过简单的字节数比较发现,对于等效的 JSON 和 XML 有效负载,前者总是小于后者。至于它们之间的差距有多大,特别是在新的 XML 压缩格式下它们 的差距有多大,有待进一步的研究。 此外,JSON 受到了擅长不同编程语言的开发人员的青睐。这是因为无论在 Haskell 中或 Lisp 中,还是在更为主流的 C#和 PHP 中,开发都可以方便地生成 JSON(详见 参考资料)。 不足 和许多好东西都具有两面性一样,JSON 的非冗长性也不例外,为此 JSON 丢失了 XML 具有 的一些特性。命名空间允许不同上下文中的相同的信息段彼此混合,然而,显然在 JSON 中已经找 不到了命名空间。JSON 与 XML 的另一个差别是属性的差异,由于 JSON 采用冒号赋值,这将导 致当 XML 转化为 JSON 时,在标识符(XML CDATA)与实际属性值之间很难区分谁应该被当作 文本考虑。 另外,JSON 片段的创建和验证过程比一般的 XML 稍显复杂。从这一点来看,XML 在开发工 具方面领先于 JSON。尽管如此,为了消除您对这一领域可能存在的困惑,下节将介绍一些最为成 熟的 JSON 开发。 从 Web services 生成 JSON 输出 既然 JSON 的首要目标是来自浏览器的信道外请求,那么我们选择 REST 风格(RESTful) Web 服务来生成这些数据。除了用典型业务逻辑探究 Web 服务之外,还将采用特定的 API 把本地 Java 结构转化为 JSON 格式(详见 参考资料)。首先,下面的 Java 代码用来操纵 Address 对象: // Create addressbook data structure SortedMap addressBook = new TreeMap(); // Create new address entries and place in Map // (See download for Address POJO structure) Address maryLebow = new Address("5 Main Street","San Diego, CA",91912,"619-332-3452","664-223-4667"); addressBook.put("Mary Lebow",maryLebow); Address amySmith = new Address("25 H Street","Los Angeles, CA",95212,"660-332-3452","541-223-4667"); addressBook.put("Sally May",amySmith); Address johnKim = new Address("2343 Sugarland Drive","Houston, TX",55212,"554-332-3412","461-223-4667"); addressBook.put("John Kim",johnKim); Address richardThorn = new Address("14 68th Street","New York, NY",,12452,"212-132-6182","161-923-4001"); addressBook.put("Richard Thorn",richardThorn); 该 Java 结构在哪里生成并不重要(可能是在 JSP、Servlet、EJB 或 POJO 中生成),重要的 是,在 REST 风格 Web 服务中有权使用这些数据。如下示: // Define placeholder for JSON response String result = new String(); // Get parameter (if any) passed into application String from = request.getParameter("from"); String to = request.getParameter("to"); try { // Check for parameters, if passed filter address book if(from != null && to != null) { // Filter address book by initial addressBook = addressBook.subMap(from,to); } // Prepare the convert addressBook Map to JSON array // Array used to place numerous address entries JSONArray jsonAddressBook = new JSONArray(); // Iterate over filtered addressBook entries for (Iterator iter = addressBook.entrySet().iterator(); iter.hasNext();) { // Get entry for current iteration Map.Entry entry = (Map.Entry)iter.next(); String key = (String)entry.getKey(); Address addressValue = (Address)entry.getValue(); // Place entry with key value assigned to "name" JSONObject jsonResult = new JSONObject(); jsonResult.put("name",key); // Get and create address structure corresponding to each key // appending address entry in JSON format to result String streetText = addressValue.getStreet(); String cityText = addressValue.getCity(); int zipText = addressValue.getZip(); JSONObject jsonAddress = new JSONObject(); jsonAddress.append("street",streetText); jsonAddress.append("city",cityText); jsonAddress.append("zip",zipText); jsonResult.put("address",jsonAddress); // Get and create telephone structure corresponding to each key // appending telephone entries in JSON format to result String telText = addressValue.getTel(); String telTwoText = addressValue.getTelTwo(); JSONArray jsonTelephones = new JSONArray(); jsonTelephones.put(telText); jsonTelephones.put(telTwoText); jsonResult.put("phoneNumbers",jsonTelephones); // Place JSON address entry in global jsonAddressBook jsonAddressBook.put(jsonResult); } // end loop over address book // Assign JSON address book to result String result = new JSONObject().put("addressbook",jsonAddressBook).toString(); } catch (Exception e) { // Error occurred } 为了便于说明,我们已将这段代码将置入 JSP(restservice.jsp)中。如果它真是一段程序,那 么类似这样的代码也会出现在 servlet 或 helper 类中。 REST 风格Web 服务首先提取两个通过 URL 请求传递给它的输入参数,根据这些值过滤现有的地址簿以适应请求。过滤过地址簿后,即可开始 循环检查 Java 映射中的每个条目。 您会注意到,在循环内部,json.org API 被广泛用于将本地 Java 格式转化为 JSON 字符串。 虽然仅使用了少量类(即 JSONArray 和 JSONObject),但 API 提供的转换方法相当广泛,甚至 能将 XML 结构转换成 JSON 输出。但回到我们的 Web 服务,一旦循环遍历了所有条目,那么变量 “result”会包含准备返回给请求方的地址簿的 JSON 同等部分。 既然已经生成了 JSON 输出,下面来看看等式的另一边:浏览器应用程序中 JSON 有效负载 的使用。 JSON 有效负载的使用 作为基于浏览器的客户端,我们的设计中大部分工作都是在 HTML、JavaScript 加上附加的 JavaScript 框架下完成的。例如利用 Prototype 库轻松创建跨浏览器样式的 Ajax 调用。下面的清 单包含了我们的应用程序的第一部分,以及相应的 JavaScript 函数。 JSON Address Book 首先导入了 prototype 库,该库用于促进对 REST 风格 Web 服务的 Ajax 调用。接下来是 searchAddressBook()函数,当用户修改其下所示的 HTML 选择列表时,将会触发此函数。该函数 被触发后,用户将会获得 HTML 选择列表中已选中的选项,并将其放入两个用于过滤地址簿的变量 中,随后定义一个指向 REST 风格服务 URL restservice.jsp 的附加变量。 此方法中还包括借助原型函数 new Ajax.Request( url, { method: 'get', parameters: pars, onComplete: showResponse }); 的实际 Ajax Web 服务调用;表明了对相关 URL 的一个请求,其 请求参数包含在 pars 中;最后一旦 Ajax 请求终止,即执行 showResponse()。 下面以 showResponse()为例说明用于评估 JSON 有效负载并将其放入 HTML 主体布局环境中 的的必要代码。 // Method invoked when page receives Ajax response from REST web service function showResponse(originalRequest) { // Get JSON values jsonRaw = originalRequest.responseText; // Eval JSON response into variable jsonContent = eval("(" + jsonRaw + ")"); // Create place holder for final response finalResponse = "" + jsonContent.addressbook.length + " matches found in range
"; // Loop over address book length. for (i = 0; i < jsonContent.addressbook.length; i++) { finalResponse += "
"; finalResponse += "Name: " + jsonContent.addressbook[i].name + "
"; finalResponse += "Address: " + jsonContent.addressbook[i].address.street + " -- " + jsonContent.addressbook[i].address.city + "," + jsonContent.addressbook[i].address.zip + ".
"; finalResponse += "Telephone numbers: " + jsonContent.addressbook[i].phoneNumbers[0] + " & " + jsonContent.addressbook[i].phoneNumbers[1] + "."; } // Place formatted finalResponse in div element document.getElementById("addressBookResults").innerHTML = finalResponse; } 此方法的输入参数是 REST 风格 Web 服务在调用时返回的响应。既然预先已经知道需要处理 JSON 字符串,那么可以利用 JavaScript eval()函数,将这个 JSON 字符串放入内存,并允许数据 访问,正是这样的简便性促使开发人员使用 JSON。完全不需要进行解析,一个简单的 eval()即可 得到 JavaScript 结构,我们可以像操纵其他任何 JavaScript 结构一样地去操纵它。 一旦 JSON 响应经过 eval 处理,将创建一个 JavaScript 循环来提取每个地址条目,并将各个 匹配项放入一个名为 finalResponse 的容器变量中。而这个容器变量本身包含所有必要的格式,用 于在页面布局中显示最终地址簿。循环结束时,匹配项也通过 document.getElementById("addressBookResults").innerHTML 放置完毕。 最后,为了保持完整,页面的实际布局由这些代码组成:

Request address book matches:

From:
To:
Results
Please select range
上面的代码清单中最值得一提的是 HTML 选择列表,因为修改触发器 Java 程序需要调用信道 外 Ajax 请求。其次,
元素就是放置格式化后的 JSON 响应的地 方。 JSON 适合您吗 就像在软件设计中编程语言的选择一样,JSON 的选择与否取决于您自身的需求。如果 Web services 使用者将在传统、功能完备的编程环境(如 Java 、.NET、PHP、Ruby 等)中创建,那 么完全可以不使用 JSON。给定大多数编程语言环境的无限制能力可提供完整的配置控制权(更不 必说对定制库、分析器或 helper 类的访问),那么 JSON 与 XML 及其他 Web services 有效载荷 之间的差别可以忽略不计。 反之,如果 Web services 使用者被限制在浏览器环境之外,那么 JSON 是值得认真考虑的对 象。 在浏览器中使用 Web services 并非兴趣使然,而是实际业务需求。如果这时需要一个加载数 据时不会出现延迟/刷新的“漂亮的 Web 2.0 界面”, 就不得不在浏览器中嵌入 Ajax 和 Web services 技术。 在这种情况下,您不仅受限于通过网络访问处理环境,而且还会受到随机用户的限制,迫使经 验丰富的开发人员用最普遍的工具在浏览器中处理文本,例如:前述的 DOM,与访问 JSON 树相 比,DOM 使用起来非常困难。 示例代码 您可下载与本文相关的代码。  json_addressbook.zip ——示例代码和实用工具 安装之前先解压下载得到的文件,将 addressbook.html,prototype-1.4.0.js 和 restservice.jsp 放入任意程序的目录下。将内含的 json.jar 复制到所选程序的/WEB-INF/lib 目录下。访问 //addressbook.html,并在 HTML 列表中进行选择。一切就绪,可以运行 JSON 了! 结束语 尽管 “Ajax”中的“x”代表 XML,Web services 也通过坚持使用 XML 格式而成为主流,但这并 不意味着这种方式无懈可击。在文本处理方面,XML 在 Ajax 程序的应用中已经暴露出一些缺点。 在这种情形下,JSON 逐渐成为引人注目的 XML 替代方案。 通过对 JSON 语法优缺点的论述,以及对如何从 REST 风格 Web services 创建 JSON 输出、 如何将其嵌入 Web 页面布局等问题的介绍,您现在应该能够为最终用户提供支持 JSON 的 Web services,接触当前提供的大量利用这一极具前途的格式的 Web services

下载文档,方便阅读与编辑

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 8 金币 [ 分享文档获得金币 ] 0 人已下载

下载文档

相关文档