Northwind遇到虚拟地球——利用Linq生成VE(虚拟地球)地图

Categories: Data, LINQ
Comments: No Comments
Published on: 2008 年 03 月 06 日

[原文作者]: Beth Massi

[原文链接]: Northwind Meets Virtual Earth – Generate VE Maps with LINQ

利用VB9Linq,你可以很容易地从多个数据源之间创建XML文件,这些数据源包括关系型数据、 XML文件和其它任何可查询对象,因为绝大多数流行的系统之间的交互都是以XML的格式进行的,所以应用是很广泛的。在VB9SOAPXAMLHTMLRSS都能够很容易地通过Linq To XML创建。比如, 如果我们想在一个VE生成的地图中显示所有Northwind库中的Customers信息,我们需要怎么做?

VE允许我们传递给它一个RSS文档,文档里面的每个item指定了纬度和经度以便能够绘制出他们在地球上的每个位置;这里有两种不同的格式可以传递,其中之一就是GeoRSS标准,我们需要做的就是通过获取customers表中包含的地址信息中的经纬度来创建这个XML,并且将这个GeoRSS传递给虚拟地球;我们可以利用http://geocoder.us 中的服务来获取在美国的Customers经纬度信息,这个服务能够从许多格式的美国地址(包括Restful RDF)中返回一组对应的经纬度信息,为了从Northwind中的customers表中创建GeoRss,我们可以在Linq查询中使用这个服务。

假设我们在Server Explorer中已经有一个到Northwind库的连接(或者其它的含有地址的数据库也可以),首先添加一个“LINQ TO SQL classes”到你的项目中,将它命名为Northwind.dbml ,并且将Customers表从Server Explorer中拖拉到设计器中,下一步就是在代码文件的头部引入Geo命名空间,因为geo命名空间的http://geocoder.us 服务将返回XML文件,我们将使用到XML文件里的地址信息。 

Imports <xmlns:geo=http://www.w3.org/2003/01/geo/wgs84_pos#>

现在我们可以写一个查询来为customers创建GeoRSS,因为Northwind库中包含的地址绝大多数是编造的,你可以将这些地址改成真实的,或者我们可以选择居住在Oregon (OR)Customers,因为那有一些有效的地址。

Dim db As New NorthwindDataContext

Dim geoRSS = _

<rss xmlns:geo=http://www.w3.org/2003/01/geo/wgs84_pos#>

    <channel>

        <title>Northwind Customer Locations</title>

        <link></link>

        <%= From Customer In db.Customers _

            Let Desc = Customer.Address & “, “ & Customer.City _

            Let Address = Customer.Address & “,” & Customer.PostalCode _

            Where Customer.Country = “USA” AndAlso Customer.Region = “OR” _

            Select <item>

                       <title><%= Customer.ContactName %></title>

                       <description><%= Desc %></description>

                       <%= GetGeoCode(Address).Descendants %>

                   </item> %>

    </channel>

</rss>

在这个查询中我们建立了GeoRSS并且调用了一个使用者,里面定义了函数GetGeoCode,该函数接受customer的地址参数,返回它的经纬度;注意,我们在查询中使用了Let关键字,目的是为descriptionaddress创建查询变量,这些变量在下面建立<item>时将会使用到。如果有结果,函数GetGeoCode将返回一个包含位置信息的XElementXElement的子方法在查询中被回调,为的是在GeoRSS中安放<geo:lat> <geo:long>节点。 

Function GetGeoCode(ByVal address As String) As XElement

    Dim url = “http://geocoder.us/service/rest/?address=” & Server.UrlEncode(address)

    Try

        Dim geo = XElement.Load(url) 

        Return <location>

                   <%= geo.<geo:Point>.<geo:long> %>

                   <%= geo.<geo:Point>.<geo:lat> %>

               </location> 

    Catch ex As Exception

        Return <location></location>

    End Try 

End Function

现在我们已经拥有了GeoRSS,可以将它传递给虚拟地球,以利用它来创建地图。例如,我们可以仅仅创建一个简单的ASP.net应用,并且将创建好的GeoRSS保存到一个Session变量中。默认页面需要有JavaScript代码,我们将利用它把GeoRSS传递到虚拟地球,并且发送一个ID”mymap”<div>块,块中定义了在页面上安放地图的区域。(想了解更多的API信息,可以看一下虚拟地球文档 

<%@ Page Language=”vb” AutoEventWireup=”false”

CodeBehind=”Default.aspx.vb” Inherits=”NorthwindVirtualEarth._Default” %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”

“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>

<html xmlns=”http://www.w3.org/1999/xhtml” >

<head runat=”server”>

    <title>Northwind Customers on Virtual Earth</title>

    <link href=”style.css” rel=”stylesheet” type=”text/css” />

    <script type=”text/javascript”

        src=”http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=5″>

    </script>

    <script type=”text/javascript”>

        var map = null;

        var layerid=1;

        function GetMap()

        {

            map = new VEMap(‘myMap’);

            map.LoadMap();  

            var l = new VEShapeLayer();

            var veLayerSpec = new VEShapeSourceSpecification(VEDataType.GeoRSS, “georss.aspx”, l);

            map.ImportShapeLayerData(veLayerSpec, null);

        }

     </script>

</head>

<body id=”body” runat=”server” >

   <form id=”form1″ runat=”server”>

   <h1>Northwind Customers on Virtual Earth</h1>

   <div id=’myMap’ style=”position: relative; width: 800px; height: 400px;”>

         <asp:Label ID=”lblStatus” runat=”server” Text=”No items found” Visible=”False”></asp:Label>

   </div>

   </form>

</body>

</html>

Default.aspxVB后台代码只是简单地做了检查,看看是否有任何从geoRSS查询中返回的<item>元素,如果有,则动态地在bodyonload事件里添加调用GetMapjavascript函数代码。 

If geoRSS…<item>.Count > 0 Then

    Session(“georss”) = geoRSS 

    Me.body.Attributes.Add(“onload”, String.Format(“GetMap()”))

Else

    Me.lblStatus.Visible = True

    Session(“georss”) = <rss></rss>

End If

另外一个页面是GeoRss.aspx,是一个空白页,仅仅返回存储在session变量中的GeoRSS,正是javascript方法需要调用的内容。 

Public Partial Class GeoRSS

    Inherits System.Web.UI.Page 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 

        Dim georss As XElement = CType(Session(“georss”), XElement) 

        Response.ContentType = “text/xml”

        Response.Write(georss.ToString()) 

    End Sub

End Class

这里关键的地方在于一个Linq查询语句中跨越了多个数据源(Northwind库和geocoder.us服务),而且只创建了一个单一的XML文档,它符合GeoRSS标准,将它传递到虚拟地球,用来产生我们的地图。正如你在这个RSS示例中所看到的,利用LinqVB9从多数据源中创建XML是非常简单地一件事。代码附件

如果你对利用WPF和你的数据创建动态地图感兴趣,不要忘记参阅WisniewskiDevCenter featured 中的文章 Create Dynamic Maps with Visual Basic 9.0 and WPF.

No Comments - Leave a comment

Leave a comment


Welcome , today is 星期六, 2017 年 02 月 25 日