




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
使用XSLT、KML和GoogleMapsAPI在地图上覆盖数据,第1部分:利用GoogleGeocoderWeb服务使用GoogleGeocoder查找邮政编码和坐标并将其存储在数据库中文档选项打印本页将此页作为电子邮件发送样例代码英文原文级别:中级JakeMiles,自由撰稿人,CondeNast2008年11月17日了解GoogleGeocoder的Web服务,它接收街道地址,返回包括经度和纬度的地址信息。在这个分为两部分的系列文章中,您将把它与GoogleMapsAPI和XSLT结合使用,以生成在GoogleMaps和GoogleEarth中显示的数据覆盖图。您将为房地产经纪公司创建一个示例应用程序,该程序允许经纪人在一个HTML表单中录入公寓列表,使用Google的GeocoderWeb服务将那些地址转换为经度和纬度,然后从公寓列表的数据库中创建KML覆盖图。在第一部分中,从用户中收集公寓列表信息来构建应用程序的前半部分,使用GoogleGeocoder的Web服务将街道地址转换为地理坐标(经度和纬度),并将坐标和地址信息存储在数据库中。GoogleMaps、GoogleEarth和Geocoder本系列的其他文章使用XSLT、KML和GoogleMapsAPI在地图上覆盖数据,第1部分:利用GoogleGeocoderWeb服务使用XSLT、KML和GoogleMapsAPI在地图上覆盖数据,第2部分:转换和使用数据GoogleMaps已经成为网络上随处可见的地图技术,它使用户可以快速生成地图、进行拖动和缩放,以及对视线范围内的街道以360度视角进行浏览。GoogleEarth提供了一本详细的地球3D百科全书,允许以各种高度对地球图像进行拖动和缩放。使用GoogleMAPSAPI可以在自己的Web页面中嵌入GoogleMaps。KML是一种用来描述地理信息(例如地标)的XML语言,它可以将可视文本数据覆盖到地图上。您也可以在GoogleEarth中导入KML数据,根据用户的拖动和缩放在Earth中显示自己的3D数据。例如,NineInchNails乐团通过下载发行他们的最新专辑“TheSlip”,并发布使用GoogleEarth和KML生成的地理下载信息,如图1所示。
图1.NineInchNails的专辑“TheSlip”的下载信息,用GoogleEarth和KML显示
这个概念暗示可以使用Google的API和KML。在KML中的下载点的经度和纬度上创建一条线,线条的高度表示该位置的下载记录数量,这些线条的高度是海拔0到与该位置的下载数量成比例的海拔高度之间的距离。该可视化中缺少的一个关键细节是将地球上客户地址(或至少是邮政编码)转换为地理坐标的能力,因为所有自定义的KML数据都使用经度、纬度和海拔坐标在地球上定位。为解决这一问题,Google近期提出了GoogleGeocoderWeb服务,它接收街道地址,返回以任意精度表示的地址的KML数据,包括经度和纬度在内。只要得到这些坐标,您就能创造性地发挥想象力,在2D地图和3D球体上覆盖文本和可视数据。
回页首GoogleMapsAPI和Geocoder服务入门要使用GoogleMapsAPI和Geocoder的GeocoderWeb服务,必须首先注册一个Google地图API键(参见参考资料获得链接),指定发送API请求(可以注册任意多个键或URL)的Web站点的URL。结果页面包含API键和一个起始HTML页面,页面中包含显示Google地图的必要JavaScript。Google地图的核心是JavaScript的load()函数(参见清单1),页面载入时调用该函数。
清单1.在页面中显示Google地图的JavaScript函数functionload(){if(GBrowserIsCompatible()){varmap=newGMap2(document.getElementById("map"));map.setCenter(newGLatLng(37.4419,-122.1419),13);}}该函数确保浏览器能够显示Google地图,创建一个地图对象(Gmap2),并在页面中为其提供HTML元素作为地图的容器(“map”)。然后使用GLatLng(经度/纬度)参数对象将地球上的一个坐标设置为它的中心,并将缩放深度(高度)指定为13。图2显示了生成的地图。
图2.在起始页面中显示的Google地图
回页首用KML提供覆盖图数据可以使用JavaScriptGoogleMAPSAPI覆盖自定义数据,例如在某位置创建几个书签,或覆盖一些带颜色的多边形和线段。然而,对于更复杂的数据(确切地说,包含更多数据点的数据)则需要使用KML文档。KML文档可以确定地址、地球上的3D坐标,以及地图上已覆盖的自定义文本和可视数据,或地球上的3D模型等地理信息。要为GoogleMaps提供KML数据,必须使用Google服务器有权访问的URL获取KML,所以必须提供服务器端的KML。在本系列的文章中,可以使用服务器端的XSLT,将数据库信息转换为可提交给GoogleMaps和GoogleEarth的KML文件,从而显示自定义数据。
回页首在数据库中存储Geocoder数据在GoogleMAPS和GoogleEarth中,地址的经度和纬度是很有用的。但是,要获得这些数据,必须调用Google的GeocoderWeb服务。这需要一些时间,所以,在数据库中存储地址时,必须同时存储地址的经度和纬度。采用该方法,您可以查询数据库,直接生成XML,并使用XSLT将返回的数据直接转换为可以在地图上覆盖的KML。为实现这些功能,可以使用两种方法调用Geocoder服务:在数据库中记录信息之前调用Geocoder服务器端在提交含有用户地址信息的表格之前,使用Google提供的JavaScript库调用Geocoder
回页首从PHP调用Geocoder首先,从PHP调用Geocoder,并使用SimpleXML模块遍历结果。recordListing()函数接收记录房地产经纪公司的公寓列表的请求参数,调用Geocoder服务,并利用结果来获得邮编和地址的地理坐标,然后在数据库中记录所有的信息(参见清单2)。
清单2.recordListing()函数(PHP)functionrecordListing($address,$aptNumber,$city,$state,$aptType,$rent,$notes){$geocoder=newGoogleGeocoder(GOOGLE_MAPS_API_KEY);$result=$geocoder->fetchAddress($address,$city,$state);//usethegeocodertomakesuretheaddressisaccurateenoughtouseif($result->getAccuracy()<GoogleGeocoderAccuracies::ADDRESS){thrownewException("Addressdoesnothaveenoughaccuracytorecordthelisting.");}//storeinthedatabasecreateListingInDb($address,$aptNumber,$city,$state,$result->getZipcode(),$result->getLongitude(),$result->getLatitude(),$aptType,$rent,$notes);}清单2中的代码演示了Geocoder结果信息的另一种使用方法—数据完整性检查。Geocoder的结果包括Accuracy度,测量输入的规范性。这里,recordListing()使用该精度进行度量(在下面的清单4中,将讨论更详细的信息)以确保信息符合规范,可以存储到数据库。
回页首GoogleGeocoder类为确保代码重用,在GoogleGeocoder类中封装对GoogleGeocoder的调用(参阅清单3)。
清单3.GoogleGeocoder类(PHP)classGoogleGeocoder{private$apiKey;private$googleGeocoderUrl='/maps/geo?';publicfunction__construct($apiKey){$this->apiKey=$apiKey;}publicfunctionfetchAddress($address,$city,$state){//encodeaddressforgoogleapicall(plusses,commas)$fullAddress=$this->encodeAddress($address,$city,$state);//createthegeocoderAPIcall$geocoderCall=$this->googleGeocoderUrl."q=$fullAddress"."&key=$this->apiKey"."&output=xml";$result=file_get_contents($geocoderCall);returnnewGoogleGeocoderResult($result);}privatefunctionencodeAddress($address,$city,$state){returnurlencode(join(",",array($address,$city,$state)));}}GoogleGeocoder类根据给定的街道地址,通过HTTP来调用geocoder服务。在它的构造函数中,接收GoogleMAPSAPI键用于HTTP调用。FetchAddress()首先对地址进行正确的编码以用于调用,然后构造调用的URL,将地址作为q参数,将GoogleMAPSAPI键作为key参数,并指定output=xml。其余的输出选项是json和csv,如果只需要地址的经度和纬度,后者将返回简化的、用逗号分隔的响应信息。最后,函数使用file_get_contents()调用URL,如果提供的字符串是以一个受支持的协议(比如HTTP)开头的话,它将像读取文件一样读取URL。
回页首GoogleGeocoder服务的响应KMLGoogleGeocoder服务将返回描述地址的KML。例如,对于地址“纽约州纽约市34大街123号”,调用将返回清单4中的XML。
清单4.地址“纽约州纽约市34大街123号”的Geocoder响应XML<?xmlversion="1.0"encoding="UTF-8"?><kmlxmlns="/kml/2.0"><Response><name>123E.34thSt.,NewYork,NY</name><Status><code>200</code><request>geocode</request></Status><Placemarkid="p1"><address>123E34thSt,NewYork,NY10016,USA</address><AddressDetailsAccuracy="8"xmlns="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0"><Country><CountryNameCode>US</CountryNameCode><AdministrativeArea><AdministrativeAreaName>NY</AdministrativeAreaName><SubAdministrativeArea><SubAdministrativeAreaName>Manhattan</SubAdministrativeAreaName><Locality><LocalityName>NewYork</LocalityName><Thoroughfare><ThoroughfareName>123E34thSt</ThoroughfareName></Thoroughfare><PostalCode><PostalCodeNumber>10016</PostalCodeNumber></PostalCode></Locality></SubAdministrativeArea></AdministrativeArea></Country></AddressDetails><Point><coordinates>-73.980182,40.746595,0</coordinates></Point></Placemark></Response></kml>响应包含一个Status,报告成功(代码200)或错误代码之一(参见参考资料获得Geocoder服务页面的错误代码表链接)。Placemark元素表示调用中指定的地址,并且根据XAL提供街道地址的结构化表示。XAL是一种可以表示世界各地的地址(这是为什么结构看起来如此复杂——它必须处理不同国家的多个不同地址结构)的可扩展地址语言。AddressDetails元素也包含一个Accuracy属性,表示XML如何详细地描述地球上的位置。例如,如果只指定“纽约州纽约市”,就会得到一个较低的Accuracy度,因为Geocoder只获得很少的信息,所以不能提供地址的更具体的信息(如邮编)。在这种情况下,它最多只能提供纽约州某个地方的经度和纬度,而不能提供更具体的信息。Accuracy不是结果的信任水平的等级或度,而是输入的规范性的度量标准。为使该XML响应更容易使用,GoogleGeocoder最后创建一个GoogleGeocoderResult对象来封装XML遍历,如清单5所示。
清单5.GoogleGeocoderResult类(PHP)classGoogleGeocoderResult{publicfunction__construct($xml){$this->xml=newSimpleXMLElement($xml);$this->resultCode=intval($this->xml->Response->Status->code);if($this->resultCode!=200){thrownewGoogleGeocoderException($this->getResultCode());}$this->placemark=$this->xml->Response->Placemark[0];$this->accuracy=intval($this->placemark->AddressDetails['Accuracy']);$coordinates=$this->placemark->Point->coordinates;$coordinatesSplit=explode(",",$coordinates);$this->longitude=$coordinatesSplit[0];$this->latitude=$coordinatesSplit[1];$this->altitude=$coordinatesSplit[2];}publicfunctiongetZipcode(){if($this->accuracy<GoogleGeocoderAccuracies::POST_CODE){thrownewException("Addressdoesnothaveenoughaccuracyforzipcode.");}return$this->placemark->AddressDetails->Country->AdministrativeArea->SubAdministrativeArea->Locality->PostalCode->PostalCodeNumber;}GoogleGeocoderResult使用PHP的SimpleXML模块使访问XML结构变得很容易。SimpleXML将一个XML文档中的元素树映射为一个PHP对象树,用属性表示子元素。SimpleXMLElement接收一个XML字符串,然后将XML子元素转换为SimpleXMLElement对象的PHP属性。如果该XML元素包含属性,也可以将SimpleXMLElement作为一个PHP关联数组进行访问,数组中的每个键表示XML元素的属性。首先,GoogleGeocoderResult构造函数从SimpleXMLElement获得响应代码:$this->resultCode=intval($this->xml->Response->Status->code);在这里,$this->xml部分是基于XML文档创建的SimpleXMLElement。当访问它的响应属性时,返回表示KML响应中的Response元素的SimpleXMLElement对象(顶层SimpleXMLElement表示XML树中的顶层KML元素)。如果一个元素包含多个相同名称的子元素,这些子元素将转换为一个数组属性。例如,假设Geocoder响应返回State元素中的多个代码,要使用$this->xml->Response->Status->code[0]访问第一个元素。SimpleXMLElement也可以显式地转换为PHP字符串,因此,可以直接将代码元素传递给intval()中,以将其转换为数字,而不是调用一种方法来获得它的文本值。当得到响应代码后,如果不是200,该构造函数抛出GoogleGeocoderException(参见示例代码),它将Geocoder错误代码映射到相应的错误消息(可以直接从Google站点的参考表中复制)。然后,构造函数使用Placemark元素(作为一个SimpleXMLElement对象)表示地球上详细的位置。您想要的其他信息全部来自它的子元素。请注意,这里的Placemark作为一个数组访问。对于一个给定的地址,Geocoder的响应可能会包含多个Placemarks,但SimpleXML允许作为一个数组访问任何元素,因为它不能区别XML是将元素作为一个数组还是一个单独的对象。接下来,它获得响应的Accuracy,以及AddressDetails元素的Accuracy属性值:$this->accuracy=intval($this->placemark->AddressDetails['Accuracy']);SimpleXMLElement使可用的属性值作为SimpleXMLElement自身的关联数组属性—SimpleXMLElement实际上同时是一个字符串,一个关联数组,和一个SimpleXMLElement对象,当遍历XML树时,允许使用高级的语法。随后,构造函数获得位置坐标的经度和纬度,结果显示为<coordinates>73.980182,40.746595,0</coordinates>—经度、纬度和海拔(当查找地址时,海拔总是0)。为了获得邮编,getZipcode()首先使用GoogleGeocoderAccuracies类确保响应是正确的,该类包含Google参考文档中的每个Accuracy值的常量(参阅参考资料)。
回页首在JavaScript中调用Geocoder除了使用PHP调用Geocoder外,还可以使用GoogleMAPSAPI库提供的GClientGeocoderJavaScript调用它。然后,在将其提交到服务器之前,用响应信息设置表单中的隐藏输入。清单6演示了这个过程。
清单6.用JavaScript调用GeocoderfunctiononSubmitAddressForm(){varaddressInput=document.getElementById('addressInput');varcityInput=document.getElementById('cityInput');varstateInput=document.getElementById('stateInput');varfullAddress=addressInput.value+","+cityInput.value+","+stateInput.value;vargeocoder=newGClientGeocoder();geocoder.getLocations(fullAddress,submitAddressFromGeocoderResponse);}add-address.php(参见下载)中的HTML表单包含要提交的地址、城市和州的文本输入,以及一个像<buttononclick="onSubmitAddressForm()">Submit</button>这样的按钮,这个按钮调用该函数处理表单提交。onSubmitAddressForm()函数从表单元素中获得房屋地址、城市和州,根据它们创建完整的地址字符串和创建一个新的GClientGeocoder对象,并调用它的getLocations()方法,然后传入要查找的完整地址以及要调用的带有响应对象的callback函数(参见清单7)。
清单7.在JavaScript中使用Geocodercallback响应functionsubmitAddressFromGeocoderResponse(response){if(!response||response.Status.code!=200){alert("Geocoderdidnotrecognizeaddress.Code="+response.Status.code);}else{varcoordinates=response.Placemark[0].Point.coordinates;varlongitude=coordinates[0];varlatitude=coordinates[1];document.getElementById('longitudeInput').value=longitude;document.getElementById('latitudeInput').value=latitude;document.getElementById('addressForm').submit();}}当GClientGeocoder接收到Geocoder服务的响应后,会以JavaScript对象符号(JSON)的格式(参见参考资料获得更多信息)调用submitAddressFromGeocoderResponse函数。JSON是日益流行的从JavaScript中获取体系结构数据的XML替代方法,因为它为JavaScript对象树提供了一种简明的、人类可读的、明确的表示法,后者与前面所示的对应的XML响应数据的结构相同。在Google的参考文档中(参见参考资料),可以看到JSON响应结构的示例。请注意,Placemark元素实际上是一个Placemarks数组,可能有多个Placemark对应一个地址。SubmitAddressFromGeocoderResponse函数与PHP代码做法一样检查响应的状态代码。与使用SimpleXML一样,SubmitAddressFromGeocoderResponse函数也使用相同的对象结构检索坐标值。然后它在页面的表单中设置隐藏输入值,接下来以编程的方式将表单提交到数据库存储起来。
回页首结束语现在,已经完成了应用程序的第一部分。调用了Geocoder服务,并在数据库中存储坐标信息。在本系列的第2部分中,将使用存储过程从MySQL查询中产生XML数据,并使用XSLT将该数据转换为KML覆盖数据,然后,GoogleMAPSAPI会在Web站点中嵌套的地图上显示KML。使用XSLT、KML和GoogleMapsAPI在地图上覆盖数据,第2部分:转换和使用数据生成KML覆盖图文档,并在GoogleMaps和GoogleEarth中显示文档选项打印本页将此页作为电子邮件发送样例代码英文原文级别:中级JakeMiles,高级技术负责人,IBM2008年11月19日在这个分为两部分的系列文章中,您将为房地产经纪公司开发一个应用程序,将所有的公寓列表显示为GoogleMaps中可点击的Placemark对象。在第1部分中,已经创建了应用程序的前半部分,从用户中收集公寓列表信息,使用GoogleGeocoderWeb服务将街道地址转换为它的地理坐标(经度/纬度),并将地理坐标和地址信息存储在数据库中。在第2部分中,您将使用这些数据生成KML覆盖图文档,并在GoogleMaps和GoogleEarth中显示。首先,在MySQL中使用存储过程生成XML数据,然后利用XSLT和一种叫做Muenchian分组的技术,将XML数据转化为包含覆盖图信息的KML文档——一个Placemark对象对应一座公寓大楼。每个Placemark对象的弹出气球显示那座楼房中的公寓列表。最后,使用GoogleMapsAPI在Web站点嵌套的GoogleMap中显示KML覆盖图。通过XSLT获取用于转换的源XML数据本系列的其他文章使用XSLT、KML和GoogleMapsAPI在地图上覆盖数据,第1部分:利用GoogleGeocoderWeb服务使用XSLT、KML和GoogleMapsAPI在地图上覆盖数据,第2部分:转换和使用数据前面已经在数据库中存储了所有的地址信息和对应的经度和纬度坐标。首先,可以用XML格式表示这些数据,然后使用XSLT样式表生成最终的KML数据。有多种解决方案可供选择。在本例中,数据库查询只返回单个表的行,您也许要编写一个PHP小函数对XML标记中的每一列进行打包。对于更复杂的数据,另外一种解决方案是使用ErikWetterberg提出的针对MySQL的巧妙存储过程,可以从MysqlForge下载。它允许直接在SQL查询中构造复杂的分级XML元素(参阅参考资料获得链接)。使用存储过程从Mysql返回XMLWetterberg的解决方案使用3种存储过程:xml_tag()、xml_escape()和xml_attr()。这3种存储过程从select语句的其余列构造一棵XML树。xml_tag()包含四个参数:标记名称、标记值(查询中数据库的列)、标记属性和标记的子元素。标记的属性和子元素都是单个字符串,因此,可以使用concat()函数连接它们。清单1说明如何使用这些存储过程来生成每行的XML元素字符串,每个字符串包含每列的一个元素。您也可以很轻松地将子元素转换为行的属性。
清单1.在PHP中使用存储过程以XML元素的形式获取MySQL结果 functionfetchListingsAsXml(){$sql=<<<SQLselectxml_tag('listing',null,null,concat(xml_tag('id',id,null,null),xml_tag('address',address,null,null),xml_tag('apt_no',apt_no,null,null),xml_tag('city',city,null,null),xml_tag('state',state,null,null),xml_tag('zipcode',zipcode,null,null),xml_tag('longitude',longitude,null,null),xml_tag('latitude',latitude,null,null),xml_tag('apt_type',apt_type,null,null),xml_tag('rent',rent,null,null),xml_tag('notes',xml_escape(notes),null,null)))asxmlfromlisting;SQL;returnfetchMysqlXml('listings',$sql);}functionfetchMysqlXml($tag,$sql){if(!$result=mysql_query($sql)){die(mysql_error());}$xml='';while($row=mysql_fetch_array($result)){$xml.=$row[0];}return"<$tag>$xml</$tag>";}SQL查询使用存储过程为每行返回数据创建一个XML列表元素,同时传递null作为列以获取值,因为它的值就是它的子元素。通用,也为参数attributes传递null值。最后,subelements参数传入一组子元素标记(每个都由进一步调用xml_tag()来生成),其中以一个选定的列作为标记的值,以null作为属性和子元素参数的值。这样,在结果集中生成每行的XML标记,但是没有创建顶层元素。为简化顶层元素的创建过程,fetchMysqlXml()函数接收顶层聚合元素的名称和查询的名称(它可能使用这些存储过程来生成XML元素字符串)。然后,在查询结果中,连接这些行中的字符串,以生成包含每行的子元素的聚合XML元素。如清单2所示。
清单2.转换为XML的数据库数据 <listings><listing><id>10</id><address>3IrvingPlace</address><apt_no>3A</apt_no><city>NewYork</city><state>NY</state><zipcode>10003</zipcode><longitude>-73.988639</longitude><latitude>40.734091</latitude><apt_type>studio</apt_type><rent>2800</rent><notes/></listing><listing><id>11</id><address>123E.34thSt.</address><apt_no>2D</apt_no><city>NewYork</city><state>NY</state><zipcode>10016</zipcode><longitude>-73.980182</longitude><latitude>40.746595</latitude><apt_type>1br</apt_type><rent>2300</rent><notes>greatviews,A/Cincl.</notes></listing></listings>
回页首将XML公寓列表转换为KML覆盖图数据因为数据库的内容是以XML格式表示的,所以可以使用XSLT将数据转换为KML格式,生成的数据可以在地图上覆盖,或导入GoogleEarth中,这将在下一节讨论。本例中的数据表示的是纽约市曼哈顿区公寓列表的清单,房东可能是个人,也可能是房地产经纪人。预期的效果是在曼哈顿区的地图上放置书签,公寓列表的每处房产对应一个书签。单击书签,将会打开一个包含书签名称和书签描述的气球,书签描述是想要在气球中显示的、有效的HTML内容。在本例中,书签弹出的气球会显示该书签对应的楼房中所有的公寓列表。您的目的是将清单2中的源XML数据转换为清单3所示的KML数据。
清单3.KML输出示例 <?xmlversion="1.0"?><kmlxmlns="/kml/2.2"><Document><name>Jake'sApartmentRentals</name><description>Amapofavailableapartments-clickabookmarktosee availableapartmentsthere.</description><Placemarkxmlns=""><name>Address220E.22ndSt.(2listings)</name><description><![CDATA[<div>APT1A:$2250,newkitchen,H/Wfloors</div><div>APT2S:$2500,loftspace,slidingglassdoors</div>]]></description><Point><coordinates>-73.982488,40.737675</coordinates></Point></Placemark><Placemarkxmlns=""><name>Address214E.73rdSt.(2listings)</name><description><![CDATA[<div>APT2C:$2000,everythingbrandnew</div><div>APT4A:$2400,elevator,A/Cincl,gorgeous</div>]]></description><Point><coordinates>-73.959088,40.769987</coordinates></Point></Placemark></Document></kml>清单3是一个包含名称元素、描述元素和Placemark元素的KML文档,每个Placemark元素表示地球上的一个位置。本文档中的每个Placemark元素都包含名称、描述和Point对象,Point对象用经度、纬度和海拔(可选)指定Placemark元素的3D坐标。每个Placemark元素在GoogleMap中都表示为一个书签。单击书签,就会打开气球,气球中的名称用粗体表示,描述的内容位于名称下方,如图1所示。
图1.在GoogleMap中显示的Placemark
注意,气球中的每个列表都自成一行。因为GoogleMaps是按照HTML格式逐字地表示描述,其中,每一行要求有<br/>标记,或者必须打包在自己的<div>元素中。可以在描述中包括任何HTML标记,但是,必须将描述字段的内容打包在CDATA元素中。创建XSLT样式表要将源XML数据转换为KML,则必须从清单4中的样式表开始。
清单4.转换为KML的XSLT样式表框架 <xsl:stylesheetversion="1.0"xmlns:xsl="/1999/XSL/Transform"><xsl:keyname="listings-by-address"match="listing"use="address"/><xsl:templatematch="/"><kmlxmlns="/kml/2.2"><Document><name>Jake'sApartmentRentals</name><description>Amapofavailableapartments-clickabookmarktoseeavailableapartmentsthere.</description><xsl:apply-templatesselect="listings"/></Document></kml></xsl:template></xsl:stylesheet>常用缩写词API:应用编程接口(applicationprogramminginterface)CSS:层叠样式表(CascadingStyleSheets)HTML:超文本标记语言(HypertextMarkupLanguage)KML:Keyhole标记语言(KeyholeMarkupLanguage)PHP:PHP超文本预处理器(PHPHypertextPreprocessor)URL:统一资源定位符(UniformResourceLocator)XML:可扩展标记语言(ExtensibleMarkupLanguage)XSLT:可扩展样式表语言转换(ExtensibleStylesheetLanguageTransformations)XSL:可扩展样式表语言(ExtensibleStylesheetLanguage)<xsl:template>标记匹配源文档的根节点,并创建包含其名称和描述的KML文档框架,然后在根节点的子元素listings上调用<xsl:apply-templates>。<xsl:key>标记位于文档的上方,允许根据地址对列表进行分组。因为每个Placemark元素都表示一座公寓大楼,其中包括很多公寓,当表示楼房的Placemark元素时,需要根据公寓大楼对列表进行分组。因为输入的XML数据包含统一的<listing>元素列表,所以在样式表中可以根据地址对这些元素进行分类。在XSLT中根据公寓大楼地址对公寓列表进行分类这里将用到一种称为Muenchian分组(参阅参考资料获得更多信息)的分组技术。该技术通过XSLT键使分组更加方便。XSLT键创建一个索引,通过该索引,可以快速找出一组与单一标准匹配的元素。这个过程创建了一个自然的分组机制,模板可使用它在KML中呈现每组的一个Placemark元素。分组行为需要样式表完成两件事:收集一组groupleader,每个groupleader表示文档中的惟一的楼房地址,用来创建Placemark元素对于每个惟一的楼房地址,将所有的地址列表传递给模板进行处理。在本例中,即在Placemark中呈现每个公寓的一个<div>元素收集惟一地址(groupleaders),开始分组过程下面的<xsl:template>元素匹配listings标记。现在开始该分组行为,如清单5所示。
清单5.listings元素的<xsl:template> <xsl:templatematch="listings"><xsl:apply-templatesselect="listing[count(.|key('listings-by-address',address)[1])=1]"mode="first-in-group"/></xsl:template>该模板的内容容可以直接用于第一个模板,但如果将其分开,代码就很容易理解。该模板调用<xsl:apply-templates>,并将文档中惟一楼房地址的列表—groupleader传递给它。选取这些groupleader元素需要稍微复杂的技巧。Xpath表达式listing[count(.|key('listings-by-address',address)[1])=1]会匹配符合括号内的条件的所有列表元素。表达式key('listings-by-address',address)访问在样式表上方创建的键。该Xpath表达式测试文档中的每个列表元素,使用当前测试的列表的地址调用键。键返回文档中具有该地址值的所有列表。[1]表示选取这些匹配元素中的第一个元素。管道符(︱)创建第一个匹配的元素与当前测试元素(句点(.)表示当前元素)的并集。因为并集只包括惟一元素(不允许重复),所以并集的结果将包括一个或两个元素—如果当前测试的元素是包含地址的文档中的第一个元素(它所在分组的首元素),那么结果中包括一个元素。如果当前测试的元素不是第一个元素(不是首元素),那么结果中包括两个元素。因此,用来测试并集结果的=1表达式只包括一个元素,这意味着当前测试的元素是包含地址的文档中的第一个元素。最后,Xpath表达式收集文档中每个惟一的楼房地址列表,并以first-in-group的模式将其传递给listing模板。组级别XSLT模板(创建KMLPlacemark)如果想要使用相同的标准对不同的环境中元素进行匹配,您可以为<xsl:template>指定不同的模式,这相当于定义两个函数,它们接收相同的参数,但是对参数采用不同的处理方式。在本例中,首先创建一组Placemark元素,然后处理组中的每个列表,它们都与vanilla列表元素匹配。创建两个匹配列表元素的<xsl:templates>。一个将为groupleader(在最后一个模板中选取)处理组级别处理过程,另外一个将处理组中每个列表的处理过程。清单6显示第一个模板。
清单6.创建组级别Placemark元素的<xsl:template> <xsl:templatematch="listing"mode="first-in-group"><Placemark><name><xsl:value-ofselect="address"/>(<xsl:value-ofselect="count(key('listings-by-address',address))"/>listings)</name><description>CDATA-START<xsl:apply-templatesselect="key('listings-by-address',address)"mode="listing-within-group"/>CDATA-END</description><Point><coordinates><xsl:value-ofselect="longitude"/>,<xsl:value-ofselect="latitude"/></coordinates></Point></Placemark></xsl:template>同样,只有模式指定为first-in-group时,该模板才匹配列表元素,就像从前一个收集groupleaders的模板中调用一样(在清单5中)。该模板为楼房创建Placemark元素,这些楼房对应的书签将出现在地图上。Placemark元素的名称是楼房的地址加上圆括号内的那座楼房中的列表号。为获得楼房的列表数量,需要再次用地址键对列表中当前地址的公寓列表计数。<description>元素是Placemark的一部分,在地图上单击Placemark时,它会出现在弹出的气球中,位于名称的下面。这里包括两个动作。首先,样式表将CDATA-START和CDATA-END两个标记放在结果XML文档中。因为结果文档是为GoogleMaps提供的KML,KML将接收描述标记的HTML内容,并将其逐字地放在Placemark元素弹出的气球中,然后将其作为文本(而不是XML)处理。因此,需要在CDATA结构体中打包<description>元素的内容。但是,不能把元素逐字放在样式表中,否则XSLT处理器会忽略它的内容。本文的解决方案是用文本标记代替CDATA的开始和结束标记,在调用的PHP代码中,使用正则表达式代替XSLT转换结果中有效的CDATA开始和结束标记,如清单7所示。处理单个列表对描述元素来说,第二件事情是调用<xsl:apply-templates>。这个行为选取当前(groupleader)列表中的所有地址清单,其中包括groupleader本身,然后将它们传递给模板,该模板以listing-within-group模式(参阅清单7)匹配清单元素。在描述元素之后,模板创建point元素,指定地图上Placemark对象的经度和纬度。如果需要的话,也可以指定海拔。
清单7.在Placemark的描述中,<xsl:template>创建每个列表的<div>元素 <xsl:templatematch="listing"mode="listing-within-group"><div>APT<xsl:value-ofselect="apt_no"/>:$<xsl:value-ofselect="rent"/>,<xsl:value-ofselect="notes"/></div></xsl:template>样式表的最后一个模板以listing-within-group模式对列表进行匹配,从而为公寓号、租金和有关公寓的各种记录的列表创建<div>元素。其中,可加入任意的HTML标记,包括CSS样式属性。用PHP对XML数据应用样式表最后一步实际上是对XML数据应用样式表。为提供XSLT转换能力,PHP5提供构建在libxslt上的XSL模块,它是一种XSL规范(参阅参考资料获得链接)的实现。XSL模块可实现对XML文档应用XSL文档,如清单8所示。
清单8.用PHP生成KML数据 functiondoXslt($xml,$xsl){$xmlDOM=DOMDocument::loadXML($xml);$xslDOM=DOMDocument::loadXML($xsl);$processor=newXSLTProcessor();$processor->importStyleSheet($xslDOM);return$processor->transformToXML($xmlDOM);}$xml=fetchListingsAsXml();$xsl=file_get_contents('listings-xml-to-kml.xsl');$kml=doXslt($xml,$xsl
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 信托与文化创意产业国际交流平台建设运营考核试卷
- 篷布制造与智能化生产技术考核试卷
- 珠海市珠海二中、斗门一中高三上学期期中联考地理试题
- 句容市2025届小升初常考易错数学检测卷含解析
- 宁夏长庆中学2025届高三月考试卷(四)生物试题含解析
- 南京工程学院《大数据思维与决策》2023-2024学年第二学期期末试卷
- 吉林省延边朝鲜族自治州延吉二中2025届高三年级四月调研考试语文试题含解析
- 山东省高青县重点名校2025年5月初三模拟考试生物试题试卷含解析
- 南京中医药大学翰林学院《建筑环境数值模拟》2023-2024学年第二学期期末试卷
- 吉林省吉林市吉林地区普通高中友好学校联合体第三十一届2025届高考仿真模拟卷(二)英语试题含解析
- 遴选会计笔试真题及答案
- 2024年中国光大银行招聘考试真题
- 2025-2030中国油漆和涂料消光剂行业市场发展趋势与前景展望战略研究报告
- 2025年储能项目可行性分析报告
- 2025年山西焦煤集团国际发展股份有限公司招聘笔试参考题库附带答案详解
- 水泥装卸合同协议
- 八年级音乐上册校园的早晨省公开课一等奖新课获奖课件
- 金华兰溪市卫健系统普通高校招聘医学类笔试真题2024
- 2025年浙江省杭州市萧山区中考一模数学模拟试卷(含详解)
- 道路普通货运企业安全生产达标考评方法和考评实施细则
- DB15T 3516-2024野生动物救护站建设规范
评论
0/150
提交评论