Bing Maps中使用Google全球本地化搜索服务详解

微软Bing Maps推出了四大在线地图服务,以满足地理位置、路由、影像以及搜索等常用GIS开发需求,去年我写的《Bing Maps开发系列博文》中介绍了这四种公关服务的特点和基本使用方法。但是很多朋友以及本人在使用这四种服务的时候发现了,使用微软提供的服务实现本地化搜索对于亚洲地区的支持不够友好,这一点比起Google还存在很大的距离。不过不用灰心,虽然Google没有像微软那样直接提供公共服务接口供开发者调用,我们还是可以通过某些手段调用Google的全球本地化搜索服务,实现功能完善的本地搜索。

 

  我们可以通过Google Maps的在线示例查看我们将要实现的功能,只不过是将Google Maps API开发的地图端给移植到了Silverlight版本的Bing Maps中。    

        

 

  首先,我们通过HttpWatch来分析此示例所发起的http请求,可获取到全球本地化搜索服务的请求路径和相关的参数,下图为HttpWatch请求跟踪截图:

    

 

  由此,我们可以得到Google全球本地化搜索服务的地址,通过分析并可得到所请求的URL地址中的q即为所查询的地点名,详细如下URL:

http://www.google.com/uds/GlocalSearch?callback=google.search.LocalSearch.RawCompletion &context =7 &rsz =small &hl =zh-CN &gss =.com &sig =3268c2f995b8fbd3048de51c45033694 & q =%E5%8C%97%E4%BA%AC &near =(39.904214%2C%20116.40741300000002) &key =ABQIAAAAjU0EJWnWPMv7oQ-jjS7dYxQ82LsCgTSsdpNEnBsExtoeJv4cdBSUkiLH6ntmAr_5O4EfjDwOa0oZBQ &v =1.0 &nocache =1298294307822

 

  实际上很多的很多的参数我们都是可以省略的,只要保持关键的请求参数同样不影响请求且能够正确的返回我们需要的结果,因此,可以对上面长段的URL地址进行瘦身,得到如下的简化版全球本地化请求地址:

http://www.google.com/uds/GlocalSearch?q=%E5%8C%97%E4%BA%AC &key =ABQIAAAAjU0EJWnWPMv7oQ-jjS7dYxQ82LsCgTSsdpNEnBsExtoeJv4cdBSUkiLH6ntmAr_5O4EfjDwOa0oZBQ &v =1.0 &nocache =1298223400032

 

  在实际使用中指需要将q参数替换为我们要搜索的地点名就可以了,因此可以将上面的URL地址改写为如下字符串格式,方便程序中灵活的设值并调用该服务。

http://www.google.com/uds/GlocalSearch? q={0} &key =ABQIAAAAjU0EJWnWPMv7oQ-jjS7dYxQ82LsCgTSsdpNEnBsExtoeJv4cdBSUkiLH6ntmAr_5O4EfjDwOa0oZBQ &v =1.0 &nocache =1298223400032

 

   做过Silverlight开发的朋友都知道,在Silverlight中发起HTTP请求会受到跨域安全性的限制,如果所请求的服务器没有配置Silverlight的安全访问策略,Silverlight所发起的HTTP请求将会产生“System.Security.SecurityException ---> System.Security.SecurityException: 安全性错误。”的异常。因此要想在Silverlight中直接向此地址发起HTTP请求是行不通的了,我们需要通过别的间接方式去实现访问该地址来达到我们的目的,实际上要做的工作就是避开HTTP访问安全性限制。

 

  通常情况下我们有两种方式可以避免HTTP请求安全访问的限制,既采用AJAX技术异步请求和在服务器端实现HTTP的同步或异步请求。接下来将要介绍的就是通过服务器端实现HTTP请求,然后将结果中转到Silverlight客户端。这里我们需要开发一个HTTP接口供Silverlight调用。

///   <summary>
///  接口实现向Google全球本地化搜索服务发起HTTP请求,然后将结果处理后返回到客户端。
///   </summary>
public   class  GoogleHandler : IHttpHandler
{
    
private   string  url  =   @" http://www.google.com/uds/GlocalSearch?q={0}&key=ABQIAAAAjU0EJWnWPMv7oQ-jjS7dYxQ82LsCgTSsdpNEnBsExtoeJv4cdBSUkiLH6ntmAr_5O4EfjDwOa0oZBQ&v=1.0&nocache=1298223400032 " ;

    
public   void  ProcessRequest(HttpContext context)
    {
        context.Response.ContentType 
=   " text/plain " ;

        
if  (context.Request.QueryString[ " q " ==   null return ;

        
string  q  =  HttpUtility.UrlEncode(context.Request.QueryString[ " q " ]).ToUpper();
        url 
=   string .Format(url, q);

        WebClient client 
=   new  WebClient();

        
string  result  =  client.DownloadString( new  Uri(url));
        result 
=  result.Substring(result.IndexOf( " GsearchResultClass " ) - 2 );
        result 
=  result.Substring( 0 , result.IndexOf( " cursor " -   3 );
            
        context.Response.Write(result);
    }

    
public   bool  IsReusable
    {
        
get
        {
            
return   false ;
        }
    }
}

 

  编译以上请求Google全球本地化搜索服务接口的HTTP接口后可以得到这样的地址:“http://localhost:28768/GoogleHandler.ashx?q={0}”,在Silverlight中就通过向自己编写的这个接口发起HTTP请求,然后此接口负责请求Google接口,实现本地上搜索功能。通过上面接口的代码可知,我特意将请求的结果进行了相应的处理,以便客户端能够更加方面的使用接口所返回的数据,其接口返回的数据为JSON格式字符串,通过上面的处理将一些不必要的数据字段给干掉了,剩下的数据我们可以定义如下实体对象。

public   class  QueryResult
{
    
public   string  GsearchResultClass {  get set ; }
    
public   string  listingType {  get set ; }
    
public   string  lat {  get set ; }
    
public   string  lng {  get set ; }
    
public   string  accuracy {  get set ; }
    
public   string  title {  get set ; }
    
public   string  titleNoFormatting {  get set ; }
    
public   string  ddUrl {  get set ; }
    
public   string  ddUrlToHere {  get set ; }
    
public   string  ddUrlFromHere {  get set ; }
    
public   string  streetAddress {  get set ; }
    
public   string  city {  get set ; }
    
public   string  region {  get set ; }
    
public   string  country {  get set ; }
    
public   string  staticMapUrl {  get set ; }
    
public   string  url {  get set ; }
    
public   string  postalCode {  get set ; }
    
public   string  maxAge {  get set ; }
    
public   string  addressLines {  get set ; }
}

 

  有了上面的实体对象,当得到请求所返回的JSON字符串后就可以通过JSON序列化既可实现JSON字符串到对象的转换,因此我们还需要定义一个JSON序列号方法以便开发中使用。

public   sealed   class  JsonHelper < T >
{
    
///   <summary>
    
///  解析JSON格式字符串为指定的对象数据结构
    
///   </summary>
    
///   <param name="jsonString"> JSON字符串 </param>
    
///   <returns> T </returns>
     public   static  T ResolveObject( string  jsonString)
    {
        DataContractJsonSerializer ds 
=   new  DataContractJsonSerializer( typeof (T));
        MemoryStream ms 
=   new  MemoryStream(Encoding.Unicode.GetBytes(jsonString));
        T t 
=  (T)ds.ReadObject(ms);

        
return  t;
    }
}

 

  到处,就只剩下最后一步了,在Bing Maps(Silverlight)中将要搜索的地名通过自己开发的接口传递给Google全球本地化搜索服务接口。下图为示例程序解决方案截图:

        

  在示例程序中提供一个文本输入空间实现地名录入,通过按钮发起请求,然后将部分结果呈现在地图指定的UI面板上,返回的数据中由于带有地理坐标(经度,纬度),还可以使用此地理坐标进行地图定位,每当成功搜索到某地名后就将地图定位带该地名所在的位置。

< StackPanel  Margin ="2"  Width ="160"  Height ="140"  VerticalAlignment ="Top"  HorizontalAlignment ="Right" >
    
< TextBox  Name ="tbAddress"  Margin ="5"  Height ="23" ></ TextBox >
    
< Button  Content ="搜索"  x:Name ="btnQuery"  Width ="70"  Height ="30"  Click ="btnQuery_Click" ></ Button >
    
< Border  CornerRadius ="8"  BorderThickness ="1"  Height ="70"  Margin ="3"  x:Name ="queryResult" >
        
< StackPanel >
        
< StackPanel.Background >
            
< LinearGradientBrush  EndPoint ="0.5,1"  StartPoint ="0.5,0" >
                
< GradientStop  Color ="#FF305867"  Offset ="0"   />
                
< GradientStop  Color ="#FFABE2F7"  Offset ="1"   />
            
</ LinearGradientBrush >
        
</ StackPanel.Background >
        
< TextBlock  Text =" {Binding city} "  Height ="23"  Margin ="0,8,0,0" ></ TextBlock >
            
< StackPanel  Orientation ="Horizontal" >
                
< TextBlock  Text =" {Binding lng} "  Height ="30"  Width ="Auto" ></ TextBlock >
                
< TextBlock  Text =","  Height ="30"  Width ="Auto" ></ TextBlock >
                
< TextBlock  Text =" {Binding lat} "  Height ="30"  Width ="Auto" ></ TextBlock >
            
</ StackPanel >
        
</ StackPanel >
    
</ Border >
    
< StackPanel.Background >
        
< LinearGradientBrush  EndPoint ="0.5,1"  StartPoint ="0.5,0" >
            
< GradientStop  Color ="#cccccc"  Offset ="0"   />
            
< GradientStop  Color ="White"  Offset ="1"   />
        
</ LinearGradientBrush >
    
</ StackPanel.Background >
</ StackPanel >

 

  在Silverlight中可以通过WebClient发起简单的HTTP请求,如下代码块所示:

///   <summary>
///  请求Google全球本地化搜索服务的接口地址
///   </summary>
private   string  service  =   " http://localhost:28768/GoogleHandler.ashx?q={0} " ;

private   void  btnQuery_Click( object  sender, RoutedEventArgs e)
{
    var address 
=   this .tbAddress.Text.Trim();
    var client 
=   new  WebClient();
    client.DownloadStringCompleted 
+=  client_DownloadStringCompleted;
    client.DownloadStringAsync(
new  Uri( string .Format(service, address), UriKind.Absolute));
}

private   void  client_DownloadStringCompleted( object  sender, DownloadStringCompletedEventArgs e)
{
    
if  (e.Error  ==   null )
    {
        
try
        {
            QueryResult result 
=  JsonHelper < QueryResult > .ResolveObject(e.Result);

            
this .queryResult.DataContext  =  result;

            
this .map.Center  =   new  Location( double .Parse(result.lat),  double .Parse(result.lng));
        }
        
catch  (Exception)
        {
        }
    }
}

 

         

 

  通过这种方式请求所得到的结果是英文的,如果要返回中文数据,只需要将Google全球本地化搜索服务的请求路径稍加修改,在请求参数中加上hl=zh-CN就行了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值