2011-06-28 39 views
7

Tôi đang xây dựng một dịch vụ web phục vụ dữ liệu ranh giới địa lý theo định dạng JSON.Định dạng lại Đa giác SQLGeography thành JSON

Dữ liệu địa lý được lưu trữ trong cơ sở dữ liệu SQL Server 2008 R2 sử dụng loại địa lý trong bảng. Tôi sử dụng phương thức [ColumnName].ToString() để trả về dữ liệu đa giác dưới dạng văn bản.

đầu ra Ví dụ:

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

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

nghĩa địa lý có thể mang hình thức của một trong hai một mảng của các cặp dài/lat xác định một đa giác hoặc trong trường hợp của nhiều định nghĩa, một mảng hoặc đa giác (multipolygon).

Tôi có regex sau đây chuyển đổi đầu ra thành các đối tượng JSON chứa trong mảng đa chiều tùy thuộc vào đầu ra.

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 
    } 

Điều này thực sự hoạt động khá tốt và chuyển đổi đầu ra DB thành JSON khi đang hoạt động để phản hồi cuộc gọi hoạt động.

Tuy nhiên tôi không có chủ regex và các cuộc gọi đến String.Replace() cũng có vẻ không hiệu quả với tôi.

Có ai có bất kỳ đề xuất/nhận xét nào về hiệu suất này không?

+0

Lưu ý: Định nghĩa địa lý chỉ dành cho GB, được phản ánh trong regex. – James

Trả lời

8

Chỉ một lần nữa để tắt chức năng này, tôi sẽ trả lời câu hỏi của riêng tôi bằng cách sử dụng giải pháp.

Phương thức này lấy đầu ra từ cuộc gọi ToString() trên MS SQL Geography Type. Nếu chuỗi được trả về có chứa dữ liệu đa giác được hình thành theo các điểm GPS, phương pháp này sẽ phân tích cú pháp và định dạng lại nó thành cú pháp JSON.

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; 
    } 
} 

Điều này đặc biệt đối với tôi, nhưng có thể hữu ích cho ai đó và thậm chí có thể tạo triển khai tốt hơn.

+0

Đây là giải pháp tốt, hoạt động tốt cho tôi –

1

Chuỗi không thay đổi trong .net, vì vậy khi bạn thay thế một số, bạn tạo bản sao đã chỉnh sửa của chuỗi trước đó. Điều này không quá quan trọng đối với hiệu suất, như đối với việc sử dụng bộ nhớ.

Nhìn vào JSON.net

Hoặc sử dụng StringBuilder để tạo đúng cách.

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

Tôi biết điều này và tôi đã sử dụng JSON.Net. Bởi vì các chuỗi không có dấu phân cách, tôi không thể nhổ chúng và sau đó thêm chúng vào đối tượng StringBuilder hoặc JSON. Tôi có thể phát hiện cặp Lat/Long nhưng khung trong sting cũng quan trọng vì nó biểu thị độ sâu của mảng, nếu không tôi chỉ có thể lấy các đối sánh của tôi và xây dựng một đối tượng JSON và không quan tâm đến các dấu ngoặc. Về cơ bản, các chuỗi này hầu như là các đối tượng JSON, chúng chỉ cần được định dạng lại thành cú pháp JSON. – James

4

Để trả lời câu hỏi của bạn về tính hiệu quả, Đối với trường hợp đặc biệt này, tôi không nghĩ rằng Thay vs RegEx sẽ là là lớn của một sự khác biệt. Tất cả chúng ta thực sự thay đổi là một số dấu ngoặc đơn và dấu phẩy. Cá nhân, tôi thích làm những việc trong TSQL cho các ứng dụng web vì tôi có thể giảm tải công việc tính toán lên Máy chủ SQL thay vì Máy chủ Web. Trong trường hợp của tôi, tôi có rất nhiều dữ liệu mà tôi đang tạo cho một bản đồ và do đó không muốn bog xuống máy chủ web với nhiều chuyển đổi dữ liệu. Ngoài ra, để thực hiện, tôi thường đặt thêm mã lực trên máy chủ SQL so với tôi làm máy chủ web, vì vậy ngay cả khi có sự khác biệt giữa hai chức năng, nếu Thay thế thì ít hiệu quả hơn. nhiêu tai nguyên hơn. Nói chung, tôi muốn máy chủ web của tôi xử lý các kết nối với máy khách và máy chủ SQL của tôi xử lý các tính toán dữ liệu. Điều này cũng giữ cho các kịch bản máy chủ web của tôi sạch sẽ và hiệu quả.Vì vậy, đề nghị của tôi là như sau:

Viết chức năng TSAR vô hướng trong cơ sở dữ liệu của bạn. Điều này sử dụng hàm SQL REPLACE và có phần là sức mạnh vũ phu, nhưng nó hoạt động thực sự tốt. Hàm này có thể được sử dụng trực tiếp trên một câu lệnh SELECT hoặc để tạo các cột được tính toán trong một bảng nếu bạn thực sự muốn đơn giản hóa mã máy chủ web của bạn. Hiện tại, ví dụ này chỉ hỗ trợ POINT, POLYGON và MULTIPOLYGON và cung cấp phần tử JSON "hình học" cho định dạng geoJSON.

GetGeoJSON Scalar Chức năng

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 

Tiếp theo, sử dụng chức năng GetGeoJSON của bạn trong bản Tuyên Bố SELECT của bạn, ví dụ:

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

Tôi hy vọng điều này cung cấp một số cái nhìn sâu sắc và giúp những người khác tìm kiếm một phương pháp , chúc may mắn!

+0

tôi nhận được hình dạng lỗi này không tương thích với địa lý – yozawiratama

+0

Bạn gặp lỗi này ở đâu? Khi gọi chức năng? Nếu vậy, nó sẽ lấy địa lý làm đối số chứ không phải hình học. –

3

Để chuyển đổi từ WKT sang GeoJson, bạn có thể sử dụng NetTopologySuite từ nuget. Thêm 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(); 

Output:

{ 
    "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

Phương pháp nêu trong câu trả lời của James hoạt động tuyệt vời. Nhưng gần đây tôi tìm thấy một lỗi khi chuyển đổi WKT nơi Longitude đã có một giá trị so với 99.

Tôi đã thay đổi biểu thức chính quy:

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

Thông báo thứ hai "2" đã được thay đổi thành một "3" để cho phép kinh độ lên tới 180.

Các vấn đề liên quan