使用 Google Mapplets 自定义 Google Maps 结果页面

使用 RSS、XSLT、PHP、KML 和 JavaScript 创建客户端和服务器端解决方案

Google Mapplet 是一个运行在 Google Maps 结果页面的应用程序,允许您将自定义的信息和行为添加到页面和地图中。在本教程中,您将编写一个 Google Mapplet,使用 Yahoo Weather RSS 提要在 Google Maps 中显示本地天气。为说明使用 Google Mapplets API 时用到的各种技术,您要实现两种解决方案。第一种是在客户端使用 RSS 和 JavaScript。第二种是在服务器端使用 XSLT、PHP、KML 和 JavaScript。

Jake Miles, 自由撰稿人和开发人员, Twistage Inc.

Jacob Miles 的照片Jake Miles 是 Twistage 公司的高级技术联络,Twistage 是一个年轻的公司,为商业公司提供完备的视频 Web 解决方案。他在语言和软件技术方面很有经验,是一名具有 10 年经验的专业开发人员,并且从 10 岁起他就一直是一个充满求知欲的学生。他还自愿参与教学工作,并且他相信如果老师讲得足够明白的话,没有人是教不会的。



Dave Wegman, 首席技术官, Twistage Inc.

David Wegman 是 Twistage 公司的首席技术官,该公司是在线视频的提供商。除了编程和技术写作之外,他还喜欢研究软件系统可用性和代码重构。他在旧金山居住和工作。



2009 年 3 月 19 日

开始之前

常用缩写词

  • Ajax:异步 JavaScript 和 XML(Asynchronous JavaScript + XML)
  • API:应用程序编程接口(application programming interface)
  • DOM:文档对象模型(Document Object Model)
  • HTML:超文本标记语言(Hypertext Markup Language)
  • HTTP:超文本传输协议(Hyper Text Transfer Protocol)
  • KML:Keyhole 标记语言(Keyhole Markup Language)
  • PHP:PHP 超文本预处理程序(PHP Hypertext Preprocessor)
  • RSS:真正简单的连锁(Really Simple Syndication)
  • URL:统一资源定位符(Uniform Resource Locator)
  • W3C:万维网联盟(World Wide Web Consortium)
  • XHTML:可扩展超文本标记语言(Extensible Hypertext Markup Language)
  • XML:可扩展标记语言(Extensible Markup Language)
  • XSL:可扩展样式表语言(Extensible Stylesheet Language)
  • XSLT:XSL 转换(XSL Transformations)

本教程适用于有兴趣将自定义的信息和行为添加到 Google Maps 结果页面的 Web 应用程序开发人员。您需要熟悉 PHP、JavaScript 和 XSLT 方面的知识。

关于本教程

在本教程中,将构建一个 Google Mapplet,使用 Yahoo Weather RSS 提要显示本地的天气。在 Google Mapplets API 中使用 Ajax 请求类,调用一个反向地理编码服务(参阅 先决条件 获得链接),将 Google Map 中当前的坐标转换为邮编。

您将实现两种解决方案:一种方案是在 JavaScript 中调用 Yahoo 的天气服务,在侧边栏中显示天气。另外一种方案是调用自己的远程 Web 服务器,在地图上放置一层 KML 覆盖层(overlay)。远程 Web 服务器运行 PHP 5.2, 使用 XSL 模块对 Yahoo 返回的 RSS XML 应用 XSLT 样式表。将实现两种样式表:一种样式表将 Yahoo RSS 数据转换为一种更简单的数据结构,将表示层(KML)与外部数据结构隔离,另外一种样式表将较简单的本地数据结构转换为 KML 覆盖层。最后,将覆盖层应用到 Google Map 中。

先决条件

本教程需要下列配套工具:

  • 开发 Google Mapplet 需要把它放在公共 Web 服务器上,使 Google 能够把 Mapplet 读取到缓存中以显示 Google Maps 结果页面。因此,本教程中需要访问公共 Web 服务器。可以使用 Apache Web server version 2.2 作为 Web 服务器。参阅 参考资料 获得安装和配置信息。
  • PHP 5.2.6 版本
  • geonames.org 上的反向地理编码服务。
  • 启用 JavaScript 的 Web 浏览器。
  • 喜爱的编程语言编辑器。

在 PHP 中编写 mapplet

首先,要创建 Google Mapplet 本身,使用 PHP 编写它,然后,将它添加到 Google 帐户中,因此,可以对它进行开发,并在浏览器中查看行为。Google Mapplet 是一个专门的 Google gadget 规范,所以,第一步是生成 Google gadget。在本节中,使用 PHP 编写 gadget,将 gadget XML 和它的 CDATA 部分分离到不同文件中,将 CDATA 部分分为 HTML 文件和 JavaScript 文件,分离为不同的语言使其更容易编辑。

在公共服务器上创建 weather-mapplet.php 文件

首先,创建清单 1 所示的 weather-mapplet.php 文件。

清单 1. weather-mapplet.php
<? echo('<?xml version="1.0" encoding="UTF-8"?>'); ?>
<Module>
  <ModulePrefs title="Local Weather Mapplet" 
               description="Displays local weather on the map."
               author="Jake Miles"
               author_email="jake_cnnew1@jakemiles.com"
               height="150">
    <Require feature="sharedmap"/>
  </ModulePrefs>
  <Content type="html"><![CDATA[

   <? include ('weather-mapplet-content.php'); ?>

]]></Content>

</Module>

清单 1 创建一个 mapplet gadget 规范(一个模块),并指定标题、描述、作者、作者的邮箱地址和 mapplet 的高度。mapplet 规范需要 <Require feature="sharedmap"> 标记。它需要页面中有一个共享的地图(Google Map)。

将 HTML 重构到另外一个 PHP 文件中

清单 1 中的下一个元素 Content 指定 CDATA 元素内的 mapplet 的内容。不要对 CDATA 元素的 mapplet 进行编码,在大多数的编辑器中,这是很难实现的,可以将 HTML 的内容重构到 weather-mapplet-content.php 中,如清单 2 所示。

清单 2. weather-mapplet-content.php
Ladies and jellyspoons, your local weather...

<div>
  Units: 
  <input id="units-english" type="radio" name="weather-units" checked> English
  <input id="units-metric" type="radio" name="weather-units"> Metric
</div>

<div>
  Result behavior: <br/>
  <input id="results-simple" type="radio" name="result-type" checked> 
Client-side  <br/>
  <input id="results-server-xslt" type="radio" name="result-type"> 
Server-side XSLT
</div>

<div id="message">

</div>

<script>
   <? include ('weather-mapplet-content.js'); ?>
   runMapplet();
</script>

清单 2 指定将 HTML 加载到 Google Maps 结果页面的左侧(参见图 1)。它包括一对单选按钮,可以选择天气信息的英制计量或公制计量,另外一组单选按钮可以选择实现路径,因为在本教程中,要实现两种解决方案。当调试 JavaScript 代码时,清单 2 中的消息 div 可作为一个输出控制台,而且,可以使用它在 Yahoo Weather 提要中显示天气摘要。

图 1. 最终的本地天气 mapplet
最终的本地天气 mapplet

添加 JavaScript

JavaScript 本身被重构到 weather-mapplet-content.js 文件中,这样更容易编辑,而且可以分离不同类型的代码。weather-mapplet-content.php 包含 JavaScript 文件,所以当呈现时,JavaScript 文件显示为内嵌的内容(在一个可调用的 URL 中集合 Google Gadget 规范),但是您仍然可以编辑它自己的文件。

HTML 片段加载后,调用 Javascript 函数 runMapplet()(在后面的 开发 Javascript 中定义)启动 mapplet 功能。RunMapplet() 函数放在 weather-mapplet-content.js 中。整个 JavaScript 文件是比较长的,可以在本教程附带的 源代码 包中找到它。清单 3 显示了 JavaScript 文件的开始部分,现在您拥有了所有 PHP 包含链(在本教程的后面部分,您将逐行浏览这个文件)。

清单 3. weather-mapplet-content.js
var map = new GMap2();
var mapCenter;

function runMapplet () {  .......

现在,可以将 mapplet 的 URL 添加到 Google Maps 页面中,在继续对功能进行编码之前,可以查看它最初的形式。您将构建功能并在此过程中在页面中进行调试。

weather-mapplet-content.js 的顶端声明两个公共变量,mapmapCenter,将 map 设置为 Gmap2 的一个新实例。Gmap2 表示页面的 Google Map。mapCenter 存储后面使用的地图的中心坐标。


将 mapplet 添加到 Google Maps 中

这时,可以将 mapplet 添加到 Google Maps 页面,并确认它能够运行。但是,在这之前需要先安装 Google Mapplets Developer Mapplet。这是必须的,因为 Google 通常将 mapplet 代码存到缓存中,意味着如果您只是重新加载页面,那么开发期间所做的任何改变都不会在 mapplet 中显示。Developer Mapplet 为 mapplet 添加一个重载链接,允许您清除 mapplet 的缓存,并重新加载它。

安装 developer mapplet

下一步是将 mapplet 添加到 Google 帐户中,因此,您可以在开发阶段了解它的运转情况。要确认您需要添加它(参见图 2),请访问

http://maps.google.com/ig/add?synd=mpl&pid=mpl&moduleurl=
http://www.google.com/ig/modules/geodeveloper.xml

注意:上面的 URL 以多行显示仅仅是为了格式的目的。当把它复制到浏览器中时,需要将其变为一串字符。

图 2. 添加 Google Mapplet Developer Mapplet
添加 Google Mapplet Developer Mapplet

单击 Add it to Maps 将其添加到您的帐户中。

将 Mapplet 添加到 Google Maps 中

接下来,将 Mapplet 添加到 Google Maps 帐户中。请访问 Google Maps 目录

http://maps.google.com/ig/directory?synd=mpl&pid=mpl&features=
sharedmap,geofeed&backlink=http%3A%2F%2Fmaps.google.com%2Fmaps%2Fmm

注意:上面的 URL 以多行显示仅仅是为了格式的目的。当把它复制到浏览器中时,需要将其变为一串字符。

单击 Add by URL(参见图 3)。

图 3. Google Maps Directory 的 Add By URL 链接
Google Maps Directory 的 Add By URL 链接

单击 Add by URL,将看到一个需要添加的 mapplet 的 URL 的提示。指定公共 Web 服务器上 weather-mapplet.php 的 URL,然后单击 Add(参见图 4)。

图 4. 指定 mapplet 的 URL
指定 mapplet 的 URL

Google 会警告您,您正在将一个非 Google 创建的特性添加到 Google Maps 页面中(参见图 5)。

图 5. 添加第三方 mapplet 时 Google 发出警告
添加第三方 mapplet 时 Google 发出警告

单击 OK 添加 mapplet,然后单击页面左上角的 Back to Google Maps 返回到 Google Maps 页面。如果搜索一个地址,则在搜索结果中单击 My Maps,将在地图列表的左侧同时看到 Mapplet Developer mapplet 和 Local Weather mapplet(参见图 6)。

图 6. 运行在 Google Maps 中的 Developer Mapplet 和您的 mapplet
运行在 Google Maps 中的 Developer Mapplet 和您的 mapplet

开发 JavaScript

JavaScript 是 mapplet 的中心内容。在本节中,开始介绍 JavaScript ,这样就有了一个完整的 PHP 包含链 — 包括的文件链构成 URL 的结果。一个是 mapplet 规范,其中包含 mapplet 的 HTML,后者包含的是 JavaScript 文件。一旦这三个部分准备好之后,就可以开始应用程序功能的开发。

添加 runMapplet() 函数

Mapplet 的骨架显示在 Google Maps 结果页面后,可以继续开发 JavaScript 以利用它的功能。将 runMapplet() 函数添加到 weather-mapplet-content.js 中,如清单 4 所示。

清单 4. runMapplet() (weather-mapplet-content.js)
function runMapplet () {
  GEvent.addListener(map, "moveend", function() {          
    map.getCenterAsync (onGetCenter);
  });
}

这是在 mapplet 的 HTML 内容的 <script> 标记中调用的函数。意味着当页面加载时函数就被调用。RunMapplet() 将 mapplet 设置为响应页面地图中的位置变化事件。

RunMapplet() 不直接对地图进行操作。它为 moveend 地图事件添加一个监听程序,提供一个函数对象,当地图改变位置后(例如,当用户用鼠标拖动地图),该函数对象被调用。产生的事件会驱动其他的 mapplet 行为。在 Google Maps API 中调用的许多函数必须用 Mapplets API 中相应的异步函数代替。

调用 getCenter() 函数

该回调函数本身就可得到地图的中心坐标,用 GLatLng 对象表示一个纬度/经度对。回调函数与在简单的 Google Maps API 组件中相比看起来有所不同。用 mapplets API 中对 getCenterAsync() 的调用代替 Google Maps API 中对 getCenter() 的调用。调用 getCenterAsync() 需要 onGetCenter 回调函数。onGetCenter() 函数通过地图的中心坐标调用,这与 getCenter() 的调用相反,后者直接返回坐标。

因此,runMapplet() 为地图的移动设置侦听程序,当地图发生移动后,监听程序要求地图提供其中心纬度/经度对,提供 onGetCenter 作为回调函数。因此,当地图的中心位置改变时,使用新的地图中心调用函数 onGetCenter(参阅清单 5)。

清单 5. onGetCenter() 函数
function onGetCenter (center) {
  mapCenter = center;
  var reverseGeocoderUrl = createReverseGeocoderUrl (center);
  document.getElementById("message").innerHTML = 'Looking up zipcode from ' + 
reverseGeocoderUrl;
  _IG_FetchXmlContent (reverseGeocoderUrl, onReverseGeocoderResult);
}

function createReverseGeocoderUrl(gLatLng) {
    return 'http://ws.geonames.org/findNearbyPostalCodes?lat=' + gLatLng.lat() + 
'&lng=' + gLatLng.lng();
}

使用地图的中心 GLatLng 对象调用 onGetCenter(),该对象表示地图的纬度/经度坐标。将 GLatLng 对象存储在全局变量 mapCenter 中,这样做主要是为了避免在后面的 JavaScript 中使用地图中心时重复异步调用。而且,将 mapplet 中的消息 div 中的文本设置为状态信息,这表示可以很容易地在 JavaScript 中访问 mapplet 的 HTML 元素,即使 mapplet 在 Google Maps 页面内运行。

将地图中心转换为邮编

尽管 Google Map 可以提供它的中心坐标,但是,Yahoo weather RSS 提要需要的是邮编,而 Google map 不提供中心坐标对应的邮编。因此,为实现两者之间的映射,使用一个免费的反向地理编码服务(参阅 先决条件 获得链接),接收纬度和经度,并返回描述几个附近的邮编的 XML。

设置全局变量 mapCenter 之后,onGetCenter() 使用地图的中心对象 GLatLng 调用 createReverseGeocoderUrl(),生成反向地理编码 URL。

要调用这个 URL,使用 Google Maps API 函数 _IG_FetchXmlContent,这将加载 URL 的内容,将其作为 XML 进行解析,并生成一个 DOM 对象。这个调用是异步的,所以可以和 getCenterAsync() 一样,提供一个回调函数。在本例中,回调函数为 onReverseGeocoderResult,如清单 6 所示。

清单 6. onReverseGeocoderResult
function onReverseGeocoderResult (data) {
    var zipcodes = data.getElementsByTagName("code");
    if (zipcodes.length == 0) {
      document.getElementById("message").innerHTML = 
'No zipcode information available for the current map location.';
    } else {
      var firstCode = zipcodes[0];
      var postalCodeDom = firstCode.getElementsByTagName('postalcode')[0];
      var zipcode = postalCodeDom.textContent;
      onZipcodeObtained (zipcode);
    }
}

用一个 DOM 对象调用 onReverseGeocoderResult,该对象表示反向地理编码服务调用的 XML 结果。可以通过在浏览器中调用反向地理编码器查看结果。例如,反向地理编码器调用

http://ws.geonames.org/findNearbyPostalCodes?
lat=40.746135271984336&lng=-73.97892951965332

会生成清单 7 所示的 XML(此处简略列出)。

注意:上面的 URL 以多行显示只是为了满足格式目的。当把它复制到浏览器中时,需要将其变为一串字符。

清单 7. Geonames.org Reverse Geocoder 服务返回的 XML 示例
<geonames>
 <code>
   <postalcode>10016</postalcode>
   <name>NewYork</name>
   <countryCode>US</countryCode>
   <lat>40.746135271984336</lat>
   <lng>-73.97892951965332</lng>
   <adminCode1>NY</adminCode1>
   <adminName1>NewYork</adminName1>
   <adminCode2>061</adminCode2>
   <adminName2>NewYork</adminName2>
   <adminCode3/>
   <adminName3/>
   <distance>0.0</distance>
 </code>
 <code>
   <postalcode>10158</postalcode>
   <name>NewYork</name>
   <countryCode>US</countryCode>
   <lat>40.749435</lat>
   <lng>-73.9758</lng>

 ...

</geonames>

XML 包含给定的纬度/经度对附近的邮编的结构化地址信息。

将结果信息作为一个 DOM 对象提供给 onReverseGeocoderResult 函数,该函数调用 getTagsByElementName(),获取所有名为 code 的标记。如果服务没有为坐标对返回邮编,那么 onReverseGeocoderResult() 将在 mapplet 的消息 div 中报告。另外,本例中只想要一个邮编,而不是附近的所有邮编。因此,onReverseGeocoderResult() 使用文档中的第一个 <code> 元素查找它的 postalcode 元素,并获得 textContent 值,就得到用字符串表示的邮编。然后,使用邮编调用 onZipcodeObtained()(参阅清单 8)。

清单 8. onZipcodeObtained()
function onZipcodeObtained(zipcode) {
  var unitsEnglishRadio = document.getElementById('units-english');
  var units = unitsEnglishRadio.checked ? 'f' : 'c';
  var serverXsltRadio = document.getElementById('results-server-xslt');
  if (serverXsltRadio.checked) {
    fetchServerXsltResults(zipcode, units);
  } else {
    fetchYahooRss (zipcode, units);
  }
}

用地图中心对应的邮编调用 onZipcodeObtained()。然后,查看哪个计量单位单选按钮被选中,然后查看哪个功能路径被选中:客户端还是服务器端 XSLT。如果服务器端路径被选中,调用 fetchServerXsltResults(),否则,调用 fetchYahooRss(),并传递邮编和计量单位(华氏温度或摄氏温度)。fetchServerXsltResult() 使用服务器端路径,调用 KML 覆盖层的 PHP 脚本,fetchYahooRss() 在 JavaScript 中直接调用 Yahoo RSS 提要,并显示它的摘要。


客户端路径

在 Local Weather Mapplet 的示例中,两个单选按钮确定执行哪个行为路径:一个表示在客户端执行,另外一个表示主要在服务器端执行。在本节中,将实现客户端路径,在 JavaScript 中读取 Yahoo Weather RSS,并完全显示它。

调用 Yahoo RSS Weather 服务

客户端路径中的第一步是通过调用 fetchYahooRss() 来调用 Yahoo RSS Weather 服务,如清单 9 所示。

清单 9. fetchYahooRss()
function fetchYahooRss(zipcode, units) {
  var yahooWeatherRssUrl = createYahooRssUrl(zipcode, units);
  _IG_FetchXmlContent (yahooWeatherRssUrl, onYahooWeatherRssResult);
}

function createYahooRssUrl(zipcode, units) {
    return 'http://weather.yahooapis.com/forecastrss?p=' + zipcode + '&u=' 
+ units;
}

fetchYahooRss() 调用 createYahooRssUrl,传递邮编和单位表示,创建 Yahoo! Weather RSS 提要的 URL。然后,使用 Google Maps 中的 _IG_FetchXmlContent 函数异步读取该 URL 的结果,提供 onYahooWeatherRssResult 作为回调函数。

为了查看 Yahoo! Weather RSS 提要的示例结果,在浏览器中访问 http://weather.yahooapis.com/forecastrss?p=10016&u=f 查看页面源代码,它包含结构如清单 10 所示的 XML。

清单 10. Yahoo! Weather RSS 提要的示例结果
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<rss version="2.0" xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0"
 xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
  <channel>
    <title>Yahoo! Weather - New York, NY</title>
<link>http://us.rd.yahoo.com/dailynews/rss/weather/New_York__
   NY/*http://weather.yahoo.com/forecast/10016_f.html</link>
<description>Yahoo! Weather for New York, NY</description>
<language>en-us</language>
<lastBuildDate>Sun, 05 Oct 2008 7:51 pm EDT</lastBuildDate>
<ttl>60</ttl>
<yweather:location city="New York" region="NY"   country="US"/>

<yweather:units temperature="F" distance="mi" pressure="in" speed="mph"/>
<yweather:wind chill="56"   direction="60"   speed="3" />
<yweather:atmosphere humidity="90"  visibility="6"  pressure="30.28"  
rising="1" />
<yweather:astronomy sunrise="6:57 am"   sunset="6:31 pm"/>
<image>
<title>Yahoo! Weather</title>
<width>142</width>
<height>18</height>
<link>http://weather.yahoo.com</link>
<url>http://l.yimg.com/us.yimg.com/i/us/nws/th/main_142b.gif</url>
</image>
<item>

<title>Conditions for New York, NY at 7:51 pm EDT</title>
<geo:lat>40.67</geo:lat>
<geo:long>-73.94</geo:long>
<link>http://us.rd.yahoo.com/dailynews/rss/weather/New_York__
NY/*http://weather.yahoo.com/forecast/10016_f.html</link>
<pubDate>Sun, 05 Oct 2008 7:51 pm EDT</pubDate>
<yweather:condition  text="Fair"  code="33"  temp="56"  
date="Sun, 05 Oct 2008 7:51 pm EDT" />
<description><![CDATA[
<img src="http://l.yimg.com/us.yimg.com/i/us/we/52/33.gif"/><br />
<b>Current Conditions:</b><br />
Fair, 56 F<BR />
<BR /><b>Forecast:</b><BR />
Sun - Partly Cloudy. High: 64 Low: 51<br />
Mon - Partly Cloudy. High: 57 Low: 43<br />
<br />
<a href="http://us.rd.yahoo.com/dailynews/rss/weather/New_York__
NY/*http://weather.yahoo.com/forecast/USNY0996_f.html">Full Forecast at Yahoo! 
Weather</a><BR/>
(provided by The Weather Channel)<br/>
]]></description>
<yweather:forecast day="Sun" date="5 Oct 2008" low="51" high="64" 
    text="Partly Cloudy" code="29" />
<yweather:forecast day="Mon" date="6 Oct 2008" low="43" high="57" 
   text="Partly Cloudy" code="30" />
<guid isPermaLink="false">10016_2008_10_05_19_51_EDT</guid>
</item>

</channel>
</rss><!-- api1.weather.ac4.yahoo.com compressed/chunked Sun Oct  
5 17:23:56 PDT 2008 -->

清单 10 包含以 RSS 格式表示的大量信息,包含一个 <channel> 元素,以及它的 <item> 子元素。有些本地天气信息放在 <channel> 层,有些信息放在 <item> 层。当在本文后面用 XSLT 转换这些数据时,数据的结构将变得更重要,但是,当前重要的元素是 <channel> 元素的 <title>,以及 <item> 元素的 <description>。

使用 Yahoo RSS 结果

URL 完全加载后,该 RSS 结果则作为一个 DOM 对象传递给回调函数 onYahooWeatherRssResult,如清单 11 所示。

清单 11. onYahooWeatherRssResult()
function onYahooWeatherRssResult(xml) {
  var item = xml.getElementsByTagName('item')[0];
  var description = item.getElementsByTagName('description')[0];
  document.getElementById("message").innerHTML = description.textContent;
}

onYahooWeatherRssResult() 在 XML 中查找 <item> 元素以及它的 <description> 元素。<description> 元素是一个方便的 HTML 呈现,用来显示天气提要中的某些信息,因此,在 CDATA 元素中对它的内容进行打包,如清单 12 所示。

清单 12. Yahoo! Weather RSS 提要结果 XML 中的 <description> 元素
<description><![CDATA[
<img src="http://l.yimg.com/us.yimg.com/i/us/we/52/33.gif"/><br />
<b>Current Conditions:</b><br />
Fair, 56 F<BR />
<BR /><b>Forecast:</b><BR />
Sun - Partly Cloudy. High: 64 Low: 51<br />
Mon - Partly Cloudy. High: 57 Low: 43<br />
<br />
<a href="http://us.rd.yahoo.com/dailynews/rss/weather/New_York__
   NY/*http://weather.yahoo.com/forecast/USNY0996_f.html">Full Forecast at 
   Yahoo! Weather</a><BR/>
(provided by The Weather Channel)<br/>
]]></description>

onYahooWeatherRssResult() 将消息 div 的内部 HTML 设置为 <description> 元素的内容,在 mapplet 的控件中提供快捷的天气摘要,在 mapplet 中单击 Reload,重新加载 Google 缓存的 mapplet。然后,将地图拖动几毫米,触发 moveend 事件(这将触发在 runMapplet() 中建立的 mapplet 监听程序,使 mapplet 遍历整个过程)。将在地图左侧看到 RSS 提要中的气象摘要,如图 7 所示。

图 7. 在 mapplet 中显示 Yahoo! Weather RSS 提要的 <description> 元素
在 mapplet 中显示 Yahoo! Weather RSS 提要的 description 元素

实现服务器端路径

现在,您已经了解了纯客户端解决方案,它通过调用 Yahoo RSS 提要,遍历结果 XML 的 DOM 对象,在 JavaScript 中显示 mapplet 的 RSS 摘要。现在该开始探讨服务器端解决方案。它包括在 JavaScript 中对 Web 服务器调用 PHP 脚本,然后调用 Yahoo 服务本身,使用 XSLT 将 RSS 转换为 KML 覆盖层,mapplet 将在地图上显示。

创建服务器端 PHP 脚本

服务器端的功能首先调用一个 PHP 脚本 weather.php,该脚本用来返回一个表示当前天气的 KML 覆盖层。首先创建 weather.php,如清单 13 所示,然后把它放到可公共存取的 Web 服务器上。

现在,将注意力转向服务器端功能路径,当在 mapplet 中选中 Server-side XSLT 单选按钮并改变地图的位置时,该功???路径被触发。它调用 fetchServerXsltResults(),如清单 13 所示。

清单 13. fetchServerXsltResults()
function fetchServerXsltResults(zipcode, units) {

  var kmlUrl = "http://YOUR-SERVER/weather.php?v=" + Math.round(Math.random() 
* 10000000000);

  var kml = new GGeoXml(kmlUrl);
  map.addOverlay(kml);
}

现在的目标是从服务器上加载 KML 文件,并将它覆盖到地图上。所以,首先该函数创建一个 URL,用来获得服务器上的 KML 数据。Google 将 KML 文件放入缓存,所以,为了确保每次都是从服务器上加载 KML,而不是从 Google 的缓存中加载,fetchServerXsltResults() 将 0 到 10000000000 之间的随机数作为虚设的请求参数添加到 URL中。

然后,使用 URL 创建一个 GGeoXml 对象。GGeoXML 实现 GOverlay 接口,意味着可以将该对象传递到 Gmap2.addOverlay() 中。与 Google Maps API 不同,mapplets API 只允许使用标准 GOverlay 类,比如 GgeoXml,而不能使用自定义的 GOverlay 实现。为了在地图上覆盖 KML 数据,GGeoXml 加载一个 XML 文件,并用它调用 addOverlay

实现服务器端功能

这将实现服务器端功能,可以使用 PHP 和 XSLT 将 Yahoo! Weather RSS 提要转换为在 Google Map 上覆盖的 KML 文件。继续创建 weather.php,如清单 14 所示,将其放在公共 Web 服务器上。

清单 14. weather.php
<?php

require_once('yahoo-weather-rss.php');
require_once('XsltChainController.php');

if (! isset($_REQUEST['zipcode'])) {
  die ("zipcode request parameter required");
}

if (! isset($_REQUEST['units'])) {
  die ("units request parameter required - either c or f");
}

$weatherRss = readYahooWeatherRss ($_REQUEST['zipcode'], $_REQUEST['units']);

$controller = new XsltChainController 
  (array ('yahoo-rss-to-simple-weather.xsl',
      'simple-weather-to-kml.xsl'),
   'CDATA_START', 'CDATA_END');

echo $controller->echoTransformedXml ($weatherRss, true, false);

?>

weather.php 文件生成一个 KML 文件,mapplet 将该文件覆盖到 Google Map 上。首先,要确保存在需要的请求参数,使用邮编和单位表示(c 或 f)来调用 Yahoo RSS 提要。然后,调用 readYahooWeatherRss(),传递这些参数,并收回 Yahoo Weather RSS 提要的 XML。接下来,创建 XsltChainController 类的一个实例,指定一组 XSLT 样式表文件以逐次应用到源 XML 文档中。另外,为 XsltChainController 提供两个标记,CDATA_START 和 CDATA_END。这两个标记允许样式表生成 CDATA 部分,否则,XSLT 样式表不能生成 CDATA 部分(生成 XSLT 样式表本身时将更详细地介绍这些内容)。最后,weather.php 使用 RSS 提要调用 XsltChainController 的 echoTransformedXml() ,将结果 XML 回传到标准输出。

在 PHP 中调用 Yahoo Weather RSS 提要

现在,需要一个主要的驱动脚本,创建清单 15 所示的 yahoo-weather-rss.php。

清单 15. yahoo-weather-rss.php
<?php

require_once('readUrl.php');

define ('YAHOO_RSS_FEED', 'http://weather.yahooapis.com/forecastrss');

function readYahooWeatherRss ($zipcode, $units) {

  if ($zipcode == null) {
    throw new Exception ("No zipcode specified");
  }

  if ($units == null) {
    throw new Exception ("No units specified");
  }

  if (! (in_array($units, array('f', 'c')))) {
    throw new Exception ("Invalid units specified (can be 'c' or 'f'): $units");
  }

  return readUrl(YAHOO_RSS_FEED . "?p=$zipcode&u=$units"); 
}

?>

yahoo-weather-rss.php 文件是非常基础的,它提供一个简单的函数 readYahooWeatherRss()readYahooWeatherRss() 确保邮编和单位参数是正确的,然后,返回使用这些参数读取 Yahoo Weather RSS 提要的结果。为获得 Yahoo RSS 提要的结果,调用清单 16 指定的 readUrl() 函数。

清单 16. readUrl.php
<?php

function readUrl($url) {
  if (ini_get('allow_url_fopen') == '1') {
    return readUrlWithFopen($url);
  } 
  else if (function_exists('curl_init')) {
    return readUrlWithCurl($url);
  } 
  else {
    throw new Exception ("readUrl: neither fopen url wrapppers nor 
CURL support are enabled.");
  }
}

?>

readUrl.php 文件提供一个通用函数,使用 fopen 或 CURL 读取 URL 的内容,具体方法取决于当前的服务器配置。首选方法是使用 fopen()。可以通过 'allow_url_fopen' PHP 初始文件设置检测,如果 PHP 安装过程中未启用 fopen HTTP wrapper(检查方法是查看 ‘allow_url_fopen’ PHP ini 文件设置),则使用 CURL 读取 URL 内容。如果检测 ‘curl_init’ 函数并不存在,说明 CURL 也没有启用,则函数因为不能继续处理而抛出一个异常。

如果启用了 fopen() HTTP wrapper,则 readUrl() 调用 readUrlWithFopen() 函数,如清单 17 所示,因此,可以用 URL 代替本地文件路径传递给 fopen(),该函数将把它作为文件读取。

清单 17. readUrlWithFopen()
function readUrlWithFopen($url) {

  $contents = file_get_contents($url);

  if (! $contents) {
    throw new Exception ("readUrl: Couldn't read url: $url");
  }
    
  return $contents;
}

readUrlWithFopen() 使用 file_get_contents() 函数读取 URL 的内容。然后,确保函数从 URL 中读取某些内容,如果内容为空,则抛出异常。否则,返回 URL 的内容。

另外一个选择是清单 18 所示的 readUrlWithCurl()

清单 18. readUrlWithCurl()
function readUrlWithCurl($url) {

  $ch = curl_init();
  try {

   curl_setopt($ch, CURLOPT_URL, $url);

   curl_setopt($ch, CURLOPT_HEADER, 0);

   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

    $content = curl_exec($ch);
    curl_close($ch); 
    return $content;

  } catch (Exception $e) {
    curl_close($ch); 
    throw new Exception ("Couldn't read url using CURL: $e");
  }
}

readUrlWithCurl() 使用 curl_init() 创建 CURL 处理程序。然后,设置要调用的 URL,指定不返回 HTTP 头部,只返回响应的内容,并指定返回内容而不是将其直接写到标准输出中。设置选项后,调用 curl_exec()curl_close() 读取流,然后关闭流,这样可以捕获任何异常,并确保关闭 CURL 流以避免资源一直处于打开状态。

在 PHP 5 中使用 XSL 模块实现 XSLT 样式表转换的方法

脚本检索到 Yahoo Weather RSS 提要的内容后,可以将其转化为更容易被使用的内容。为此,创建一个 XsltChainController 实例,如清单 19 所示。

清单 19. XsltChainController
class XsltChainController {

  private $stylesheets;
  private $cdataStart;
  private $cdataEnd;

  public function __construct ($stylesheets, $cdataStart=null, $cdataEnd=null) {

    $this->stylesheets = $stylesheets;
    $this->cdataStart = $cdataStart;
    $this->cdataEnd = $cdataEnd;

    if ($cdataStart != null && $cdataEnd == null ||
    $cdataEnd != null && $cdataStart == null) {
      throw new Exception ("XsltChainController: if providing cdataStart or cdataEnd, 
must provide both.  Only one provided.");
    }
  }

XsltChainController 将一系列 XSLT 样式表应用到源 XML 文档中。它的构造函数接收一组样式表文件路径、可选的 $cdataStart$cdataEnd 参数。这些指定标记可能出现在样式表中,用来指定结果 XML 中 CDATA 部分的开始和结束位置。这样就解决了一个问题:如果样式表要通过转换生成 CDATA 部分的主体,在 XSLT 样式表的输出中就不能包含真正的 CDATA 部分(与 <![CDATA[...stuff...]] 一样)。XSLT 处理程序发现 CDATA 部分后,就会对内容进行转义,忽略 CDATA 中要生成转换内容的 XSLT 元素。解决方法是在 XSLT 样式表中 CDATA 部分的开始处和结束处插入一个标记,在 XSLT 处理完成后,用封闭的处理程序代替实际的 CDATA 开始和结束标记。

构造函数只需配置控制器。接下来,添加 echoTransformedXml() 函数完成这一任务,如清单 20 所示。

清单 20. echoTransformedXml()
public function echoTransformedXml ($xml, $stripCdata=false) {

    if ($stripCdata) {
      $xml = $this->stripCdata($xml);
    }

    $transformedDom = $this->applyStylesheets ($xml);

    echo ($this->cdataStart 
      ? $this->replaceCdataMarkers ($transformedDom->saveXML())
      : $transformedDom->saveXML());
  }

protected function stripCdata($xml) {
    return str_ireplace (array('<![CDATA[', ']]>'), 
             array ('', ''), 
             $xml);
  }

  protected function replaceCdataMarkers ($xml) {
    return str_ireplace (array ($this->cdataStart, $this->cdataEnd),
             array ('<![CDATA[', ']]>'), 
             $xml);
  }

echoTransformedXml() 接收 XML 和一个标志,XML 要作为字符串进行转换,标志指定是否去除源文档中的 CDATA 标记。这样做的原因是,源文档可能包含 CDATA 部分,而 CDATA 部分包含样式表需要访问的 XHTML。在 Yahoo RSS 提要中,<item> 元素的 <description>,即包含天气的 HTML 摘要的 CDATA 部分,包含当前天气状况的有意义的图标。如果图标仍然在 CDATA 元素中,那么样式表不能使用这个图标。所以,在应用样式表链之前,该函数首先通过调用 stripCdata() 从源文档中去掉所有的 <!CDATA[[ and ]] 标记。类似地,如果构造函数接收了 $cdataStart$cdataEnd,那么 echoTransformedXml() 将在处理样式表之后,用真正的 CDATA 开始和结束标记来代替它们,允许样式表生成自己的 CDATA 部分。在两个 CDATA 处理步骤之间,调用 applyStylesheets 转换 XML,如清单 21 所示。

清单 21. XsltChainController.applyStylesheets()
protected function applyStylesheets ($xml) {
    $xmlDOM = DOMDocument::loadXML ($xml);
    foreach ($this->stylesheets as $stylesheet) {
      $xmlDOM = $this->applyStylesheet ($xmlDOM, $stylesheet);
    }
    return $xmlDOM;
  }

首先,applyStylesheets() 用 XML 字符串创建一个 DOMDocument 对象。然后,对提供的一组样式表文件路径进行遍历,用数组中每个元素调用 applyStylesheet(),传入源 XML 或 applyStylesheet() 的前一个调用的结果,直至依次应用所有样式表为止。清单 22 显示的 applyStylesheet()DOMDocument 对象应用了一个 XSLT 样式表。

清单 22. XsltChainController.applyStylesheet()
protected function applyStylesheet ($xmlDOM, $xslFile) {

    $processor = new XSLTProcessor();    

    $xslDOM = DOMDocument::load ($xslFile);
    
    $processor->importStyleSheet($xslDOM);
    
    return $processor->transformToDoc($xmlDOM);
  }

applyStylesheet() 接受保存待转换的 XML 的 DOMDocument,以及要应用到 XML 的 XSLT 样式表的文件路径。使用 PHP 5 中的 XSL 模块执行转换。 applyStylesheet() 创建一个 XSLTProcessor,根据 XSLT 样式表文件路径创建 DOMDocument,将样式表的 DOMDocument 导入到 XSLTProcessor 中,然后调用它的 transformToDoc() 方法,对源 DOMDocument 进行转换,返回转换后的 DOMDocument 对象。


创建 XSLT 样式表

现在,了解了将 XSLT 样式表应用到 XML 文档的方法后,可以创建样式表本身,将 Yahoo RSS 转换为 Google Mapplet 中的 KML。将对 Yahoo RSS 依次应用两个样式表。第一个样式表将其转换为更易管理的数据结构,第二个样式表将较简单的数据结构转换为最终的 KML。

使用 XSLT 简化数据结构

清单 10 中可以看出,Yahoo RSS 提要包含大量信息,结构有些复杂。另外,因为它来自外部组织,可能会随时改变数据的结构,因此,先将它转换为一个较简单的本地数据结构,可以不受这些改变影响。只要有一个中间 XSLT 样式表,可以将 Yahoo 的格式转换为本地格式,那么就可以设计最终的 KML,而不用考虑 Yahoo 的数据结构。创建中间样式表 yahoo-rss-to-simple-weather.xsl 的开始部分,如清单 23 所示。

清单 23. yahoo-rss-to-simple-weather.xsl
<xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
        xmlns:yweather="http://weather.yahooapis.com/ns/rss/1.0">

</xsl:stylesheet>

创建样式表的骨架部分,在 xmlns:xsl 行为 XSLT 指定 XML 的名称空间。geo 名称空间包含在 Yahoo RSS 提要中,yweather 名称空间也包含在 RSS 提要中。如果不定义名称空间,那么样式表不能识别那些名称空间中的元素。

接下来,添加一个模板,匹配 RSS 提要的 <channel> 元素,如清单 24 所示。

清单 24. 与 /rss/channel 匹配的 XSLT 模板
<xsl:template match="/rss/channel">
    <weather>

      <data-source>
    <link><xsl:value-of select="link"/></link>
    <icon><xsl:value-of select="image/url"/></icon>
      </data-source>     

      <xsl:apply-templates select="item/title"/>

      <xsl:apply-templates mode="coordinates"
               select="item"/>

      <xsl:apply-templates mode="condition-icon"
               select="item/description/img"/>

      <xsl:apply-templates mode="units"
               select="*[local-name()='units']"/>

      <xsl:apply-templates mode="condition"
               select="item/*[local-name()='condition']"/>

      <xsl:apply-templates mode="wind" 
               select="*[local-name()='wind']"/>

      <xsl:apply-templates mode="atmosphere" 
               select="*[local-name()='atmosphere']"/>

      <xsl:apply-templates mode="astronomy" 
               select="*[local-name()='astronomy']"/>

    </weather>
  </xsl:template>

该模板匹配 /rss/channel 元素,生成结果文档中的顶级 <weather> 元素。创建 <data-source> 元素,指定信息源。<data-source> 元素包含一个 <link> 元素,指定信息源的 URL,它的值来自源文档的 /rss/channel/link 元素(Yahoo Weather 的链接)。另外,还包含一个 <icon> 元素,将包含 Yahoo Weather 图标的 /rss/channel/image/url 元素的值作为它的值。然后,对源文档中的一些 Xpath 应用模板 — 首先是 /rss/channel/item/title 元素,然后是一些其他的数据元素。

其他模板应用的不同之处在于它们都指定 mode 属性。<xsl:apply-templates> 接收 select 属性,它指定将作为参数传递到模板的节点的 Xpath。另外,还包含一个可选的 mode 属性。mode 属性可以改变您对待 XSLT 模板的方式。模式没有为模板提供特定的 match 属性,而是允许把这些属性当作函数调用,与一个没有模式的模板相比,模式会更紧密地匹配一个模板应用。为使模板规范更简单,对 <xsl:apply-templates> 的每一个调用都指定传入模板的节点和模式。如果样式表中的每个模板都给定自己的模式,那么就不用指定必须匹配的对象 — 可以用星号(*)字符进行匹配。例如,清单 25 显示坐标模式的模板。

清单 25. “coordinates” 模式的模板
<xsl:template mode="coordinates" match="*">
    <coordinates>
      <latitude><xsl:value-of select="geo:lat"/></latitude>
      <longitude><xsl:value-of select="geo:long"/></longitude>
    </coordinates>      
  </xsl:template>

因为该模板指定了一个模式,用星号(*)表示与任何节点匹配,如果使用这个模板的模式调用 <xsl:apply-templates>,将与该模板进行匹配。这将其转换为一个更常规的函数调用,而不用重新指定要应用模板的 Xpath 表达式。现在将由模板的调用方使用正确的 Xpath 表达式(必须这样做)调用它。该方法简化了模板规范,将模板转换为函数。另外,可以创建两个模板,应用于相同类型的节点,但是生成不同的结果。例如,使用 <item> 元素调用 coordinates 模板,生成 <item> 的 <geo:lat> 和 <geo:long> 元素的 <coordinates> 元素。还可以定义其他的模板,使用 <item> 元素进行调用,从中提取不同的信息。

回顾 清单 24 中的 /rss/channel 模板,可以了解为什么需要去掉源文档中的 CDATA 元素标记。其中一个模板应用是 <xsl:apply-templates mode="condition-icon" select="item/description/img"/>。它使用 RSS 提要中的 <description> 的 <img> 标记调用 condition-icon 模板(使用这一模式的模板),因为要逐字输出模板,所以它最初包含在 CDATA 元素中。现在,去除 CDATA 标记后,该模板可以像获得源文档中其他 XML 元素一样获得 <img> 元素。

清单 24 中另外一个关注点是模板调用 <xsl:apply-templates mode="units" select="*[local-name()='units']"/>。它使用 units 模式调用模板,传入不包括名称空间前缀,本地名称为 units 的所有节点。这是一种从其他名称空间选择节点的方法。在 Yahoo RSS 提要中,units 元素实际是一个 <yweather:units> 元素。Xpath 函数 local-name() 返回没有名称空间的元素的名称,因此可以更容易进行处理。在 yweather 名称空间的 condition、atmosphere 和 astronomy 元素中重复使用该方法。

units、condition、astronomy 和 atmosphere 模式的模板看起来相同,在结果文档中创建一个元素,将源元素的属性复制到该元素中,像 units 模式的模板中一样(参阅清单 26)。

清单 26. units 模式的模板
<xsl:template mode="units" match="*">
    <units>
      <xsl:copy-of select="@*"/>
    </units>
  </xsl:template>

使用 <yweather:units> 元素调用该模板,生成结果文档中的 <units> 元素,它包含源元素的所有属性(参阅 附加源代码 获得其他相似的模板定义)。

将较简单的数据结构转换为 KML 覆盖层

第一个样式表将 Yahoo RSS 文档转换为可以控制的 tamer 数据结构。转换格式后,XML 就可以被转换为 KML 文档。为实现这一功能,创建名为 simple-weather-to-kml.xsl 的样式表,如清单 27 所示。

清单 27. simple-weather-to-kml.xsl
<xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="/weather">
    <kml xmlns="http://earth.google.com/kml/2.2">
      <Document>
    <name><xsl:value-of  select="title"/></name>
    <description>Local Weather from Yahoo!</description>
    <Placemark>
      <name>Local Weather</name>
      <description>
        CDATA_START
        <xsl:apply-templates mode="placemark-description"
                 select="."/>
        CDATA_END
      </description>
      <xsl:apply-templates select="coordinates"/>
    </Placemark>
      </Document>
    </kml>
  </xsl:template>

</xsl:stylesheet>

它定义与根级别的 <weather> 元素匹配的模板,生成一个根级别的 <kml> 元素。KML 是一个指定地理信息的 XML 专用语,也可以指定地理覆盖层信息,例如地图上显示的点、线、文本或 HTML。可以使用 KML 创建一个天气信息的覆盖层,在 Google Maps 结果页面显示。KML 文档包含 <Document> 元素,<Document> 元素中包含 <name> 元素、<description> 元素,并且,在本例中,还包含一个或多个 <Placemark> 元素,每个元素都可成为地图上可单击的标记。另外,文档中还包含覆盖在地图上的线,用来绘制填充或未填充的多边形。

可以看到在 XsltChainController 的构造函数调用中指定的 CDATA_START 和 CDATA_END。它们表示结果文档中的 CDATA 部分的开始和结束,但是,该样式表不包含 CDATA 标记本身,否则 XSLT 处理程序将忽略 CDATA 部分的 <xsl:apply-templates> 元素。CDATA 部分包含的 HTML 内容将显示在 Placemark 的弹出气球中。HTML 内容在使用 placemark-description 模式的模板中被创建,如清单 28 所示。

清单 28. “placemark-description” 模板
<xsl:template mode="placemark-description" match="*">
    <div>
      <div>
    <xsl:value-of select="condition/@text"/>, 
    <xsl:value-of select="condition/@temp"/> 
<xsl:value-of select="units/@temperature"/>
      </div>
      <div>
    Wind chill: <xsl:value-of select="wind/@chill"/> 
<xsl:value-of select="units/@temperature"/> <br/>
    Wind speed: 
    <xsl:value-of select="wind/@speed"/> 
    <xsl:value-of select="units/@speed"/>
      </div>
      <div>
    Humidity: <xsl:value-of select="atmosphere/@humidity"/>%
      </div>
      <div>
    Sunrise: <xsl:value-of select="astronomy/@sunrise"/> <br/>
    Sunset: <xsl:value-of select="astronomy/@sunset"/>
      </div>
    </div>
  </xsl:template>

该模板创建在地图标记的弹出气球中显示的 HTML,列出本地天气的所有信息。请注意,如何在 <xsl:value-of select="condition/@text"/> 中访问属性,这将输出 <condition> 子元素的 text 属性的值。该模板也使用 <units> 元素,其中包含每个计量的单位和它们的值。

清单 27 中的根级别的 <weather> 元素也对源文档(<xsl:apply-templates select="coordinates"/>)中的 <coordinates> 元素应用模板,生成 placemark 的坐标,如清单 29 所示。

清单 29. 与 <coordinates> 元素匹配的模板
<xsl:template match="coordinates">
    <Point>
      <coordinates>
    <xsl:value-of select="longitude"/>,<xsl:value-of select="latitude"/> 
      </coordinates>
    </Point>
  </xsl:template>

该模板生成结果文档中的 <Point> 元素,指定 placemark 的经度和纬度对 — 在 Google Map 中的位置。

要查看应用样式表的结果,在浏览器中访问 http://YOUR-SERVER/weather.php?zipcode=10010&units=f,查看页面源代码,类似于清单 30。

清单 30. 最终的 KML 覆盖层
<?xml version="1.0"?>
<kml xmlns="http://earth.google.com/kml/2.2">
  <Document>
    <name>Conditions for Maspeth, NY at 12:18 am EDT</name>
    <description>Local Weather from Yahoo!</description>
    <Placemark>
      <name>Local Weather</name>
      <description><![CDATA[
            <div>Mostly Cloudy,  57F</div>
            <div>
      Wind chill: 57F<br/>
      Wind speed: 7mph
            </div>
            <div>
      Humidity: 88%
            </div>
            <div>
      Sunrise: 6:57 am<br/>
      Sunset: 6:30 pm
            </div>
        ]]></description>
           <Point>
             <coordinates>-73.91,40.72</coordinates>
           </Point>
     </Placemark>
  </Document>
</kml>

请注意,这里的坐标远不及 Google Maps 中的坐标精确,意味着 placemark 实际上可能被放在地图中可见窗口的外面。为纠正这一问题,将地图适当缩小以确保 placemark 可见。

实际运行 KML

现在,整个 XSLT 链都可以发挥作用,可以在 Google mapplet 进行试验。单击 Reload 重新加载 Google 缓存中的 mapplet,选择 Server-side XSLT 单选按钮,移动或缩放地图。Placemark 将在地图上显示。单击它,将会呈现 XSLT 转换创建的 HTML 天气报告,如图 8 所示。

图 8. Google Maps 中显示的本地天气 Placemark 气球
Google Maps 中显示的本地天气 Placemark 气球

结束语

小结

在本教程中,您了解了如何创建 Google Mapplet,以及如何使用 Google Mapplet API 监听地图事件并获取远程 XML 内容。另外,使用 Yahoo Weather RSS 提要,利用反向地理编码服务将纬度/经度对转换为邮编,使用 PHP 5 中的 XSL 模块和 XSLT,分离 Google Mapplet 组件规范的不同部分。这允许您从数据源中分离表示层(将 Yahoo 的数据结构转换为本地数据结构),并转换天气数据 KML 以覆盖到 Google Map 中。

现在,您可以实现自己的 Google Mapplet 想法,从 Google Mapplet API 文档中获得更多信息,希望您能从学习和实践中获得乐趣。


下载

描述名字大小
教程源代码mapplet-tutorial-source.tar80KB

参考资料

学习

  • 您可以参阅本文在 developerWorks 全球网站上的 英文原文
  • Google Mapplets API:访问首页,获得有关运行在 Google Maps 中的迷你应用程序的信息,在 Google Maps 中添加新特性或覆盖自己的数据。
  • Google Maps API:使用 JavaScript 在自己的 Web 页面中嵌套 Google Maps,创建健壮的地图应用程序来操作地图,通过各种服务为地图添加内容。
  • KML 教程:KML 是一种文件格式,用来在 Earth 浏览器(例如 Google Earth、Google Maps 和移动 Google Maps)中显示地理数据。可以从 Google 中的教程开始学习。
  • Google Maps API 注册:注册一个 Google Maps API 键。
  • Introducing Google's Geocoding Service(Jason Gilmore, developer.com):了解 Google Maps API 最新的扩展功能,允许在不使用第三方解决方案的情况下映射位置,将邮件地址转换为对应的坐标。
  • Google Maps API Reference:查找 Geocoder 服务响应的错误代码。
  • 在 IBM HTTP Server 上部署 PHP 应用(Graham Charters et al.,developerWorks,2005 年 3 月):讨论开源 Apache Web 服务器和 IBM 版本之间的差异,并查看运行众所周知的 PHP 应用程序的 IBM 版本的演示。
  • Apache 2 and PHP Installation(Dan Anderson):了解如何在 Linux™ 中同时使用 Apache 2 和 PHP 4.x(也可以使用 PHP 5.x )。
  • 将 PHP 应用程序连接到 Apache Derby(Moira Casey,developerWorks,2004 年 9 月):在这篇文章中,学习在 Windows(有些步骤适用于 Linux)中安装和配置 PHP。
  • 学习 PHP, 第 1 部分(Tyler Anderson 和 Nicholas Chase,developerWorks,2005 年 6 月):学习 PHP 基本原理。
  • 学习 PHP, 第 2 部分(Tyler Anderson 和 Nicholas Chase,developerWorks,2005 年 6 月):学习如何使用 DOM 和 SAX 将文件上传到非 web 的可存取位置。
  • 学习 PHP, 第 3 部分(Tyler Anderson 和 Nicholas Chase,developerWorks,2005 年 6 月):完成第 1 部分和第 2 部分的工作流应用程序。了解 HTTP 验证、流文件,以及如何创建对象和异常。
  • PHP 手册:了解更多有关 PHP 数据对象和它们的功能的信息。
  • PHP 联机手册:了解 PHP 5 中的 SOAP API 的参考信息。
  • 教程:JavaScript 简介JavaScript 简介:查看 w3schools.com 中更多交互式 Web 页面的潜力。
  • IBM XML 认证:了解如何才能成为一名 IBM 认证的 XML 和相关技术的开发人员。
  • XML 技术资源库:访问 developerWorks XML 专区,获得广泛的技术文章和技巧、教程、标准和 IBM 红皮书。
  • developerWorks 技术活动和网络广播:随时关注技术的最新进展。
  • 技术书店:浏览关于这个主题和其他技术主题的图书。
  • developerWorks podcasts:收听针对软件开发人员的有趣访谈和讨论。

获得产品和技术

  • IBM 产品评估试用软件:使用可直接从 developerWorks 下载的 IBM 试用软件构建您的下一个项目,包括来自 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere® 的应用程序开发工具和中间件产品。

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML, Open source
ArticleID=376749
ArticleTitle=使用 Google Mapplets 自定义 Google Maps 结果页面
publish-date=03192009