2011-06-28 93 views
7

我正在構建一個以JSON格式提供地理邊界數據的Web服務。將SQLGeography多邊形重新格式化爲JSON

地理數據使用表格中的地理類型存儲在SQL Server 2008 R2數據庫中。我使用[ColumnName].ToString()方法作爲文本返回多邊形數據。

輸出示例:

POLYGON ((-6.1646509904325884 56.435153006374627, ... -6.1606079906751 56.4338050060666)) 

MULTIPOLYGON (((-6.1646509904325884 56.435153006374627 0 0, ... -6.1606079906751 56.4338050060666 0 0))) 

地理定義可以採取任一緯度/經度對限定多邊形的陣列或在的多個定義,陣列或多邊形(多面)的情況下的形式。

我有以下正則表達式,根據輸出將輸出轉換爲包含在多維數組中的JSON對象。

Regex latlngMatch = new Regex(@"(-?[0-9]{1}\.\d*)\s(\d{2}.\d*)(?:\s0\s0,?)?", RegexOptions.Compiled); 

    private string ConvertPolysToJson(string polysIn) 
    { 
     return this.latlngMatch.Replace(polysIn.Remove(0, polysIn.IndexOf("(")) // remove POLYGON or MULTIPOLYGON 
               .Replace("(", "[") // convert to JSON array syntax 
               .Replace(")", "]"), // same as above 
               "{lng:$1,lat:$2},"); // reformat lat/lng pairs to JSON objects 
    } 

這實際上是相當不錯的了和DB輸出到JSON在飛行轉換響應的操作調用。

但是,我不是正則表達式大師,String.Replace()的調用對我來說似乎也是低效的。

有沒有人對此有任何建議/評論?

+0

注意:地理定義僅用於GB,這反映在正則表達式中。 – James

回答

8

再次只是爲了關閉這個關閉我會回答我的問題與解決方案即時通訊使用。

此方法從一個MS SQL Geography Type上調用ToString()的輸出。 如果返回的字符串包含從GPS點構造的多邊形數據,則此方法將解析並將其重新格式化爲JSON sting。

public static class PolyConverter 
{ 
    static Regex latlngMatch = new Regex(@"(-?\d{1,2}\.\dE-\d+|-?\d{1,2}\.?\d*)\s(-?\d{1,2}\.\dE-\d+|-?\d{1,2}\.?\d*)\s?0?\s?0?,?", RegexOptions.Compiled); 
    static Regex reformat = new Regex(@"\[,", RegexOptions.Compiled); 

    public static string ConvertPolysToJson(string polysIn) 
    { 
     var formatted = reformat.Replace(
         latlngMatch.Replace(
         polysIn.Remove(0, polysIn.IndexOf("(")), ",{lng:$1,lat:$2}") 
         .Replace("(", "[") 
         .Replace(")", "]"), "["); 

     if (polysIn.Contains("MULTIPOLYGON")) 
     { 
      formatted = formatted.Replace("[[", "[") 
           .Replace("]]", "]") 
           .Replace("[[[", "[[") 
           .Replace("]]]", "]]"); 
     } 

     return formatted; 
    } 
} 

這是特定於我的apllication,但也許對某人有用,甚至可能創建一個更好的實現。

+0

這是一個很好的解決方法,對我來說工作正常 –

1

字符串在.net中是不可變的,所以當你替換某些字符串時,你可以創建一個以前字符串的編輯副本。這對於性能並不那麼關鍵,對於內存使用情況來說也是如此。

JSON.net

或者使用StringBuilder正確地生成它。

StringBuilder sb = new StringBuilder(); 
sb.AppendFormat(); 
+0

我知道這一點,我已經使用JSON.Net。因爲字符串沒有分隔符,所以我不能將它們吐出來,然後將它們添加到StringBuilder或JSON對象中。我可以檢測Lat/Long對,但是Sting中的包圍也很重要,因爲它表示數組的深度,否則我可以只取我的匹配並構建一個JSON對象而不關心括號。基本上這些字符串幾乎都是JSON對象,只需要將其重新格式化爲JSON語法即可。 – James

4

要獲得關於效率的問題,對於這個特殊的情況下,我不認爲更換 VS 正則表達式將是那麼大的差別。我們真正改變的是一些括號和逗號。就我個人而言,我更喜歡在TSQL中爲Web應用程序做事情,因爲我可以將計算工作卸載到SQL Server而不是Web Server上。在我的情況下,我爲地圖生成了很多數據,因此不想讓大量數據轉換陷入網絡服務器。另外,爲了提高性能,我通常在SQL服務器上比在網絡服務器上放置更多的功能,所以即使兩個功能之間存在一些差異,如果替換爲效率不高,它至少由具有許多服務器的服務器來處理更多資源。通常,我希望我的Web服務器處理與客戶端的連接,並且我的SQL服務器處理數據計算。這也讓我的網絡服務器腳本保持清潔和高效。所以我的建議如下:

在您的數據庫中編寫一個標量TSQL函數。這使用SQL函數,並且有點暴躁,但它表現得非常好。如果您真的想要簡化您的Web服務器代碼,則可以直接在SELECT語句上使用此函數,或者在表中創建計算列。目前這個例子只支持POINT,POLYGON和MULTIPOLYGON,併爲geoJSON格式提供了「geometry」JSON元素。

GetGeoJSON標量函數

CREATE FUNCTION GetGeoJSON (@geo geography) /*this is your geography shape*/ 
RETURNS varchar(max) 
WITH SCHEMABINDING /*this tells SQL SERVER that it is deterministic (helpful if you use it in a calculated column)*/ 
AS 
BEGIN 
/* Declare the return variable here*/ 
DECLARE @Result varchar(max) 

/*Build JSON "geometry" element for geoJSON*/ 

SELECT @Result = '"geometry":{' + 
    CASE @geo.STGeometryType() 
     WHEN 'POINT' THEN 
      '"type": "Point","coordinates":' + 
      REPLACE(REPLACE(REPLACE(REPLACE(@geo.ToString(),'POINT ',''),'(','['),')',']'),' ',',') 
     WHEN 'POLYGON' THEN 
      '"type": "Polygon","coordinates":' + 
      '[' + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@geo.ToString(),'POLYGON ',''),'(','['),')',']'),'], ',']],['),', ','],['),' ',',') + ']' 
     WHEN 'MULTIPOLYGON' THEN 
      '"type": "MultiPolygon","coordinates":' + 
      '[' + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@geo.ToString(),'MULTIPOLYGON ',''),'(','['),')',']'),'], ',']],['),', ','],['),' ',',') + ']' 
    ELSE NULL 
    END 
    +'}' 

    /* Return the result of the function*/ 
    RETURN @Result 

END 

接下來,用你GetGeoJSON功能在你的SELECT語句,例如:

SELECT dbo.GetGeoJSON([COLUMN]) as Geometry From [TABLE] 

我希望這提供了一些見解,並幫助他人尋找方法, 祝你好運!

+0

我得到這個錯誤幾何與地理不兼容 – yozawiratama

+0

你從哪裏得到這個錯誤?在調用函數時?如果是這樣,它將地理作爲參數,而不是幾何。 –

3

要從WKT轉換到GeoJson,您可以使用nuget中的NetTopologySuite。添加NetTopologySuiteNetTopologySuite.IO.GeoJSON

var wkt = "POLYGON ((10 20, 30 40, 50 60, 10 20))"; 
var wktReader = new NetTopologySuite.IO.WKTReader(); 
var geom = wktReader.Read(wkt); 
var feature = new NetTopologySuite.Features.Feature(geom, new NetTopologySuite.Features.AttributesTable()); 
var featureCollection = new NetTopologySuite.Features.FeatureCollection(); 
featureCollection.Add(feature); 
var sb = new StringBuilder(); 
var serializer = new NetTopologySuite.IO.GeoJsonSerializer(); 
serializer.Formatting = Newtonsoft.Json.Formatting.Indented; 
using (var sw = new StringWriter(sb)) 
{ 
    serializer.Serialize(sw, featureCollection); 
} 
var result = sb.ToString(); 

輸出:

{ 
    "features": [ 
    { 
     "type": "Feature", 
     "geometry": { 
     "type": "Polygon", 
     "coordinates": [ 
      [ 
      [ 
       10.0, 
       20.0 
      ], 
      [ 
       30.0, 
       40.0 
      ], 
      [ 
       50.0, 
       60.0 
      ], 
      [ 
       10.0, 
       20.0 
      ] 
      ] 
     ] 
     }, 
     "properties": {} 
    } 
    ], 
    "type": "FeatureCollection" 
} 
1

在詹姆斯的回答中列出的方法的偉大工程。但是I轉換WKT當其中經度超過99,

有值I改變正則表達式最近發現一個錯誤:

@"(-?\d{1,2}\.\dE-\d+|-?\d{1,3}\.?\d*)\s(-?\d{1,2}\.\dE-\d+|-?\d{1,2}\.?\d*)\s?0?\s?0?,?" 

通知第二「2」已變更爲「3」至允許經度上升到180.