在 Ajax 中进行 XML 处理,第 2 部分: 两种使用 Ajax 和 XSLT 的方法,在 Ajax 中使用 XSLT 转换 XML

21 篇文章 0 订阅

本系列文章分析了实现天气面板的四种不同方法。第一部分中介绍的一种办法是利用一种 Apache Web 服务器规则将 NWS XML 数据代理给浏览器。然后通过 JavaScript 代码从 DOM 提取需要的数据,转变为 HTML 格式再显示出来。

这一部分介绍第二和第三种方法。这两种办法有一点是共同的,即都使用 XSLT。

XSLT

常用缩写词
  • DOM:文档对象模型(Document Object Model)
  • HTML:超文本标记语言(Hypertext Markup Language)
  • XML:可扩展标记语言(Extensible Markup Language)
  • XSLT:可扩展样式表语言转换(Extensible Stylesheet Language Transformation)

XSLT 是一种查询 XML 并将其转换成其他格式的语言。这恰恰是我们所要对天气数据做的工作 — 以 XML 格式存储,但需要某种对用户(或者浏览器)更友好的格式。 NWS 数据中有些是天气面板所不需要的。需要某种技术提取需要的数据。XSLT 可以同时满足这两方面的要求。

本教程不是为了详细介绍 XSLT。关于 XSLT 的更多信息请参阅 developerWorks 文章 “What kind of language is XSLT?”(参见 参考资料)。

和其他很多计算机语言不同,XSLT 语法是有效的 XML。如果习惯于 C、Java™、Perl 或 Python 语言,可能会造成一点麻烦。

由于这两种方法都使用 XSLT,我们首先来看看它。然后再介绍如何纳入总体解决方案。

使用 XSLT 转换数据

首先看看 NWS XML 数据格式。清单 1 显示了压缩后的例子。


清单 1. 示例 NWS XML 数据文件 KNGU.xml(有删减)

<? xml version="1.0" encoding="ISO-8859-1" ?>  
< current_observation  version ="1.0"
 xmlns:xsd
="http://www.w3.org/2001/XMLSchema"
 xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation
=
 "http://www.weather.gov/data/current_obs/current_observation.xsd"
>
 
< credit > NOAA's National Weather Service </ credit >
 
< credit_URL > http://weather.gov/ </ credit_URL >
 
< image >
 
< url > http://weather.gov/images/xml_logo.gif </ url >
 
< title > NOAA's National Weather Service </ title >
 
< link > http://weather.gov </ link >
 
</ image >
 
< suggested_pickup > 15 minutes after the hour </ suggested_pickup >
 
< suggested_pickup_period > 60 </ suggested_pickup_period >
 
< location > Norfolk, Naval Air Station, VA </ location >
 
< station_id > KNGU </ station_id >
 
< latitude > 36.94 </ latitude >
 
< longitude > -76.28 </ longitude >
 
< observation_time >
                Last Updated on Jan 7, 2:53 pm EST
                
</ observation_time >
 
< observation_time_rfc822 >
 Mon, 7 Jan 2008 14:53:00 -0500 EST
 
</ observation_time_rfc822 >
 
< weather > Fair </ weather >
                
< temperature_string > 74 F (23 C) </ temperature_string >
 
< temp_f > 74 </ temp_f >
 
< temp_c > 23 </ temp_c >
 
< relative_humidity > 34 </ relative_humidity >
                
< wind_string > From the Southwest at 9 Gusting to 18 MPH </ wind_string >
 
< wind_dir > Southwest </ wind_dir >
 
< wind_degrees > 240 </ wind_degrees >
 
< visibility_mi > 10.00 </ visibility_mi >
                
< icon_url_base >
                http://weather.gov/weather/images/fcicons/
                
</ icon_url_base >
                
< icon_url_name >
                skc.jpg
                
</ icon_url_name >
 
< disclaimer_url > http://weather.gov/disclaimer.html </ disclaimer_url >
 
< copyright_url > http://weather.gov/disclaimer.html </ copyright_url >
 
< privacy_policy_url > http://weather.gov/notice.html </ privacy_policy_url >
</ current_observation >

我们只对 清单 1 中突出显示的数据感兴趣,因此 XSLT 的首要任务是提取需要的元素。接下来将这部分数据转换成 HTML 以显示到浏览器中。

清单 2 显示了达成这两个目标的 XSLT 程序。


清单 2. weather2html.xsl,天气数据 XSLT 程序

< xsl:stylesheet  version ="1.0"  
xmlns:xsl
="http://www.w3.org/1999/XSL/Transform" >

 
< xsl:output  method ="html"   />

 
< xsl:template  match ="/current_observation" >

 
< center >
 
< b >< xsl:value-of  select ="location"   /></ b >< br />
 
< xsl:value-of  select ="weather"   />< br />

 
< xsl:variable  name ="icon_url_base"  select ="icon_url_base" />
 
< xsl:variable  name ="icon_url_name"  select ="icon_url_name" />

 
< img  border ='0'  src ='{$icon_url_base}{$icon_url_name}'/><br/>
 
<xsl:value-of select ="temperature_string"   />< br />
 Wind: 
< xsl:value-of  select ="wind_string"   />< br />
 Humidity: 
< xsl:value-of  select ="relative_humidity"   /> % < br />
 Visibility: 
< xsl:value-of  select ="visibility_mi"   />  miles < br />
 
< br />< span  style ='font-size:  0.8em; font-weight: bold;' >
 
< xsl:value-of  select ="observation_time"   /></ span >< br />

 
</ center >

 
</ xsl:template >

</ xsl:stylesheet >

首先注意这一行:

<xsl:output method="html" />

它告诉 XSLT 处理程序输出的是 HTML 而不是默认的 XML 格式。

XSLT 程序看起来似乎是 HTML 和 XML 的混合,的确如此。任何以 <xsl: 开始的 XML 元素都是 XSLT 语言的语句。其他的则是直接输出的文本。

比如这一行:

<b><xsl:value-of select="location" /></b><br/>

xsl:value-of 元素要求 XSLT 处理程序找到 XML 输入文件中的 location 元素,提取元素值,在 xsl:value-of 标记所在的位置输出。结果如下所示:

<b>Norfolk, Naval Air Station, VA</b><br/>

XSLT 处理程序

和其他编程语言如 Perl、Ruby 一样,XSLT 的执行也是通过语言解释程序完成的。通常称之为 XSLT 处理程序。但 XSLT 不是一种通用 编程语言 — 只能转换一种 XML 数据文件。因此多数 XSLT 处理程序需要两个输入文件:XSLT 程序和转换的 XML 文件。

很多 Linux® 版本都包含称为 xsltproc 的 XSLT 命令行处理程序。和其他类似的工具一样,调试和优化 XSLT 脚本非常方便。

Xsltproc 需要两个参数:XSLT 程序及其操作的 XML。假设我已经下载了 Norfolk Naval Air Station in Virginia 的 NWS XML 数据到 KNGU.xml 文件中(KNGU 是第 1 部分所说的四字符气象站惟一标识符)。可以用该命令测试 清单 2 中的 XSLT 程序:

xsltproc weather2html.xsl KNGU.xml

XSLT 处理程序把 weather2html.xsl 中的转换规则应用于输入文件 KNGU.xml 并把结果写入标准输出。结果如 清单 3 所示。


清单 3. KNGU.xml XSLT 处理结果

< center >
< b > Norfolk, Naval Air Station, VA </ b >< br >
Fair
< br >
< img  border ="0"  
 src
="http://weather.gov/weather/images/fcicons/skc.jpg" >< br >
57 F (14 C)
< br >
Wind: From the West at 7 MPH
< br >
Humidity: 58%
< br >
Visibility: 7.00 miles
< br >
< br >
< span  style ="font-size: 0.8em; font-weight: bold;" >
 Last Updated on Oct 12, 7:53 am EDT
</ span >
< br >
</ center >

方法 2:XSLT 在服务器上

我打算在天气面板中采用 XSLT 方法。方法 2 中,服务器端脚本从 NWS 服务器获取数据,使用 XSLT 把 XML 转换为 HTML 然后将其返回到浏览器。浏览器将返回的 HTML 片段插入 DIV 标记。

图 1 显示了该方法中使用的数据管道。数据从 NWS 服务器流动到我的服务器,服务器端脚本将 XML 转换为 HTML。管道的重点是浏览器,接收 HTML 并插入到 Web 页面中。


图 1. 方法 2 的数据管道
方法 2 的数据管道

我需要一个能执行 XSLT 转换的服务器端程序。该程序用 Perl 编写,如 清单 4 所示,其他语言也很容易实现。该脚本通过浏览器上的 XMLHttpRequest 调用激活。Ajax JavaScript 传递给服务器端脚本一个参数:从 NWS 服务器检索 XML 数据所需要的四字符 NWS Station ID。


清单 4. weather_xml2html.cgi Perl 脚本

# ! / usr / bin / perl

use  strict ;

my 
$ DATA_DIR  =   " /var/www/html/xml_weather/data " ;
my 
$ XSL_FILE  =   " $DATA_DIR/weather2html.xsl " ;
my 
$ XSLTPROC  =   " /usr/bin/xsltproc " ;
my 
$ HTTP_BIN  =   " /usr/bin/wget -q -O -  " ;
my 
$ URL_FORMAT  =   " http://www.nws.noaa.gov/data/current_obs/%s.xml " ;

#  Get the NOAA location key:
my 
$ location  =   $ ENV{QUERY_STRING} ;

#  Minimal sanity check of the location key:
if   ($ location !~  / ^[ d w]{ 4 } $/)  {
 
print   " Content-type: text/html " ;
 
print   " Unknown location ($location). " ;
 
exit   1 ;
}

#  Build URL:
my 
$ url  =  sprintf  ($ URL_FORMAT ,   $ location );

#  Build  Command :
my 
$ cmd   =   " $HTTP_BIN '$url' 2> /dev/null | $XSLTPROC $XSL_FILE -  " ;

print   " Content-type: text/html " ;

open 
( my  $ IPIPE ,   " $cmd | " );
while 
(<$ IPIPE >)  {
 
print   $ _ ;
}
close 
$ IPIPE ;

Apache Web 服务器运行 清单 4 所示的脚本。Apache QUERY_STRING 环境变量向脚本提供四字符的 Station ID。

Perl 脚本使用两个外部命令:xsltprocwgetXsltproc 即前面所述的命令行 XSLT 处理程序。Wget 是一个免费工具(可从 Free Software Foundation 下载)。多数 Linux 发行版已经预安装了该程序。Wget 可从 Web 上抓取 Web 页面(或其他 Web 资源)。Perl 脚本使用 wget 从 NWS 服务器获取 XML 文件。

如果在 Linux 命令行中执行,Perl 脚本将构造一个命令管道,如下所示:

/usr/bin/wget -q -O - http://www.nws.noaa.gov/data/current_obs/KNGU.xml /
| /usr/bin/xsltproc /var/www/html/xml_weather/data/weather2html.xsl -

使用外部程序
一些程序员可能对实现这么简单的一个 Ajax Web 服务使用外部程序感到吃惊。Comprehensive Perl Archive Network (CPAN) 资料库包含成千上万个 Perl 模块。其中很多可用于代替 wgetxsltproc。但使用这两个工具,weather_xml2html.cgi 脚本更容易改为其他语言实现,如 Python 或 Ruby。多数脚本语言都能把外部程序的结果导入脚本。事实上,我建议您使用所选语言提供的库或者模块。

该命令的输出被读入 Perl 脚本并发送到标准输出。要记住,脚本是通过浏览器 JavaScript 代码调用 XMLHttpRequest 激活的,因此结果作为响应返回到浏览器。

和方法 1 不同,这里不需要 Apache 代理规则。weather_xml2html.cgi 脚本就像一个智能代理,而且由于脚本在服务器上,从而避免了第 1 部分所述的同一域 问题(参见 参考资料)。

服务器返回格式化的天气面板 HTML,因此客户端的天气面板库就很简单了。清单 5 显示第二种方法所用的 JavaScript 代码。


清单 5. weather_badge()weather_badge_intel_proxy.js 实现

function weather_badge (nws_id, div_name)  {
 var ajax 
= new Ajax 
 (
"/cgi-bin/xml_weather/weather_xml2html.cgi?",
 nws_id,
 
"GET",
 function (req) 
{
 var div 
= document.getElementById (div_name);
 div.innerHTML 
= req.responseText;
 }

 );
 ajax.request ();
}

weather_badge() 的这个版本只需要调用服务器脚本(提供适当的 NWS 站点 ID),然后使用 innerHTML 属性将返回的 HTML 插入 DIV 标记。

优缺点

这种方法把更多的处理任务放在 Web 服务器上。如果访问服务器的用户少,或者服务器有大量内存和处理器周期可用,这种方法就能很好地工作。

类似的,如果确知用户使用落后的老式桌面电脑,这种方法也合适。浏览器没有多少工作:发送请求然后等待服务器完成大部分的任务。

方法 3:客户端 XSLT

天气面板的第三种实现也用到 XSLT。这一次 XSLT 处理在浏览器中完成。使用的 weather2html.xsl XSLT 程序(清单 2)仍然相同。图 2 显示了这种方法使用的数据管道。


图 2. 方法 3 的数据管道
方法 3 的数据管道

主流浏览器(Microsoft® Windows® Internet Explorer®、Firefox 和 Opera)都支持相同形式的 XSLT 处理。Firefox 和 Opera 实现了 XSLTProcessor 对象。Internet Explorer 通过扩展 Document 模型实现 XSLT 处理。

清单 6 显示了方法 3 的 weather_badge() 实现。和方法 1 相同,必须设置 Apache Web 代理规则以便浏览器能够访问 NWS 服务器(要记住 Ajax 应用程序只能访问提交原始 Web 页面的同一台服务器上的数据。关于同一域问题请参阅第 1 部分) 。


清单 6. weather_badge()weather_badge_cs_xslt.js 实现

function  weather_badge (nws_id, div_name)  {

 
// Get the XML file from the server.

 
var ajax = new Ajax ("/nws_currobs/" + nws_id + ".xml""""GET"null);
 ajax.setAsync (
false);
 ajax.request ();
 
var xml_doc = ajax.req.responseXML;

 
// Get the XSLT from the server.

 ajax 
= new Ajax ("/xml_weather/data/weather2html.xsl""""GET"null);
 ajax.setAsync (
false);
 ajax.request ();
 
var xsl_doc = ajax.req.responseXML;

 
var div = document.getElementById (div_name);

 
// Use object detection to find out if we have
 // Firefox/Mozilla/Opera or IE XSLT support.

 
if (typeof XSLTProcessor != "undefined"{
 
var xsl_proc = new XSLTProcessor ();
 xsl_proc.importStylesheet (xsl_doc);
 
var node = xsl_proc.transformToFragment (xml_doc, document);

 div.innerHTML 
= "";
 div.appendChild (node);
 }

 
else if (typeof xml_doc.transformNode != "undefined"{
 div.innerHTML 
= xml_doc.transformNode (xsl_doc);
 }

 
else {
 div.innerHTML 
= "XSLT not supported in browser.";
 }

}

方法 1 中需要从 NWS 服务器检索 XML 文件。这种新的方法也需要从我自己的服务器上检索 XSLT 文件。清单 6 的前半部分是提取这些文件到 weather_badge() 函数中的代码。分别作为 JavaScript Document 对象 xml_docxsl_doc 通过 XMLHttpRequest 返回。

weather_badge() 函数的后半部分应用 XSLT 转换。由于 Internet Explorer 的处理方式和其他浏览器不同,需要确定运行的浏览器类型。通过对象检测 来完成。利用 JavaScript typeof 运算符检查是否存在执行转换需要的对象。

如果定义了 XSLTProcessor,则使用的是 Firefox 或 Opera 浏览器。于是实例化新的 XSLTProcessor 对象并导入 XSLT 样式表。然后利用该对象的 transformToFragment 方法转换 XML 天气数据。这种方法返回文档片段而不是 HTML 文本。就是说和前两种方法不同,不能使用 innerHTML 将结果插入 DIV 标记。办法很简单:通过 appendChild 很容易将得到的文档片段插入页面的 DOM 树。

若没有定义 XSLTProcessor 但定义了 transformNode 方法,则假定 JavaScript 程序在 Internet Explorer 中运行。这种情况下只需要一行代码来执行 XSLT 转换并将结果插入 DIV 标记:

div.innerHTML = xml_doc.transformNode (xsl_doc);

优缺点

第三种方法结合了前两种方法的一些部分。Apache Web 代理把 XML 返回浏览器进一步处理,XSLT 完成从 XML 到 HTML 的转换。

方法 1 只需要直接访问 DOM 树中的数据元素,与此相比,浏览器中的 XSLT 处理程序需要更多的计算资源。对于这个简单的例子,用户可能觉察不到额外的计算时间。但是如果 XML 非常大或者 XSLT 转换很复杂,用户可能难以忍受浏览器显示结果的延迟。

另一方面,手动操作大型 XML 文件的复杂 DOM 树可能造成 JavaScript 代码难以编写和维护。

还需要考虑用户使用的浏览器和计算机。是有足够内存和处理器能力的高端工作站还是老式的落后计算机?其答案决定了是否能够执行复杂的 JavaScript XSLT 处理。

下载

描述名字大小下载方法
本系列的示例代码x-xmlajax.zip194KBHTTP
关于下载方法的信息


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值