我正在构建一个以JSON格式提供地理边界数据的Web服务。
使用表中的地理类型将地理数据存储在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 :(得分:10)
再次只是为了关闭这个,我将使用解决方案回答我自己的问题。
此方法从MS SQL ToString()
上的Geography Type
调用获取输出。
如果返回的字符串包含由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;
}
}
这特定于我的应用,但可能对某人有用,甚至可能创建更好的实现。
答案 1 :(得分:6)
要从WKT转换为GeoJson,您可以使用nuget的NetTopologySuite。添加NetTopologySuite和NetTopologySuite.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"
}
答案 2 :(得分:5)
要回答有关效率的问题,对于这种特殊情况,我认为替换与 RegEx 不会有太大差别。我们真正改变的是一些括号和逗号。就个人而言,我更喜欢在TSQL中为Web应用程序做事,因为我可以将计算工作卸载到SQL Server而不是Web Server上。在我的情况下,我有大量的数据,我为地图生成,因此不希望陷入网络服务器与大量的数据转换。另外,为了提高性能,我通常会在SQL服务器上放置比运行Web服务器更多的功能,因此即使两个功能之间存在一些差异,如果替换效率较低,则至少要处理由具有更多资源的服务器。一般来说,我希望我的Web服务器处理与客户端的连接以及处理数据计算的SQL服务器。这也使我的Web服务器脚本保持清洁和高效。所以我的建议如下:
在数据库中编写标量TSQL函数。这使用SQL REPLACE 函数,有点蛮力,但它表现得非常好。如果您真的想简化Web服务器代码,可以直接在SELECT语句中使用此函数,或在表中创建计算列。目前,此示例仅支持POINT,POLYGON和MULTIPOLYGON,并为geoJSON格式提供“几何”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]
我希望这能提供一些见解并帮助其他人寻找方法,祝你好运!
答案 3 :(得分:1)
字符串在.net中是不可变的,因此当您替换某些字符串时,您将创建以前字符串的编辑副本。这对于性能和内存使用并不是那么重要。
查看JSON.net
或使用StringBuilder正确生成它。
StringBuilder sb = new StringBuilder();
sb.AppendFormat();
答案 4 :(得分:1)
詹姆斯答案中概述的方法效果很好。但是我最近在转换WKT时发现了一个错误,其中经度值超过99.
我更改了正则表达式:
@"(-?\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.
答案 5 :(得分:1)
用于将空间单元格式化为 GeoJSON 的实用函数如下所示。
DROP FUNCTION IF EXISTS dbo.geometry2json
GO
CREATE FUNCTION dbo.geometry2json( @geo geometry)
RETURNS nvarchar(MAX) AS
BEGIN
RETURN (
'{' +
(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 ',''),'(','['),')',']'),'], ',']],['),', ','],['),' ',',') + ']'
WHEN 'MULTIPOINT' THEN
'"type": "MultiPoint","coordinates":' +
'[' + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@geo.ToString(),'MULTIPOINT ',''),'(','['),')',']'),'], ',']],['),', ','],['),' ',',') + ']'
WHEN 'LINESTRING' THEN
'"type": "LineString","coordinates":' +
'[' + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@geo.ToString(),'LINESTRING ',''),'(','['),')',']'),'], ',']],['),', ','],['),' ',',') + ']'
ELSE NULL
END)
+'}')
END