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

本系列文章分析了实现天气面板的四种不同方法。第一部分中介绍的一种办法是利用一种 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(有删减)

<? xmlversion="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'sNationalWeatherService </ credit >
< credit_URL > http://weather.gov/ </ credit_URL >
< image >
< url > http://weather.gov/images/xml_logo.gif </ url >
< title > NOAA'sNationalWeatherService </ title >
< link > http://weather.gov </ link >
</ image >
< suggested_pickup > 15minutesafterthehour </ suggested_pickup >
< suggested_pickup_period > 60 </ suggested_pickup_period >
< location > Norfolk,NavalAirStation,VA </ location >
< station_id > KNGU </ station_id >
< latitude > 36.94 </ latitude >
< longitude > -76.28 </ longitude >
< observation_time >
LastUpdatedonJan7,2:53pmEST
</ observation_time >
< observation_time_rfc822 >
Mon,7Jan200814:53:00-0500EST
</ observation_time_rfc822 >
< weather > Fair </ weather >
< temperature_string > 74F(23C) </ temperature_string >
< temp_f > 74 </ temp_f >
< temp_c > 23 </ temp_c >
< relative_humidity > 34 </ relative_humidity >
< wind_string > FromtheSouthwestat9Gustingto18MPH </ 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-ofselect ="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,NavalAirStation,VA </ b >< br >
Fair
< br >
< img border ="0"
src
="http://weather.gov/weather/images/fcicons/skc.jpg" >< br >
57F(14C)
< br >
Wind:FromtheWestat7MPH
< br >
Humidity:58%
< br >
Visibility:7.00miles
< br >
< br >
< span style ="font-size:0.8em;font-weight:bold;" >
LastUpdatedonOct12,7:53amEDT
</ 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 " ;

# GettheNOAAlocationkey:
my
$ location = $ ENV{QUERY_STRING} ;

# Minimalsanitycheckofthelocationkey:
if ($ location!~ / ^[ d w]{ 4 } $/) {
print " Content-type:text/html " ;
print " Unknownlocation($location). " ;
exit 1 ;
}

# BuildURL:
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 实现

functionweather_badge(nws_id,div_name) ... {
varajax
=newAjax
(
"/cgi-bin/xml_weather/weather_xml2html.cgi?",
nws_id,
"GET",
function(req)
...{
vardiv
=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) ... {

//GettheXMLfilefromtheserver.

varajax=newAjax("/nws_currobs/"+nws_id+".xml","","GET",null);
ajax.setAsync(
false);
ajax.request();
varxml_doc=ajax.req.responseXML;

//GettheXSLTfromtheserver.

ajax
=newAjax("/xml_weather/data/weather2html.xsl","","GET",null);
ajax.setAsync(
false);
ajax.request();
varxsl_doc=ajax.req.responseXML;

vardiv=document.getElementById(div_name);

//Useobjectdetectiontofindoutifwehave
//Firefox/Mozilla/OperaorIEXSLTsupport.

if(typeofXSLTProcessor!="undefined")...{
varxsl_proc=newXSLTProcessor();
xsl_proc.importStylesheet(xsl_doc);
varnode=xsl_proc.transformToFragment(xml_doc,document);

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

elseif(typeofxml_doc.transformNode!="undefined")...{
div.innerHTML
=xml_doc.transformNode(xsl_doc);
}

else...{
div.innerHTML
="XSLTnotsupportedinbrowser.";
}

}

方法 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
关于下载方法的信息


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值