9

我正在构建一个以 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()我的调用也似乎效率低下。

有没有人对此性能有任何建议/意见?

4

6 回答 6

13

再次只是为了关闭它,我将使用我使用的解决方案来回答我自己的问题。

ToString()此方法从MS SQL 上的调用中获取输出Geography Type。如果返回的字符串包含由 GPS 点构造的多边形数据,则此方法会将其解析并重新格式化为 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;
    }
}

这特定于我的应用程序,但可能对某人有用,甚至可能创建更好的实现。

于 2011-08-11T13:12:31.917 回答
12

要从 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"
}
于 2015-02-14T18:57:46.713 回答
10

为了回答您关于效率的问题,对于这种特殊情况,我认为Replace vs RegEx 不会有那么大的区别。我们真正改变的只是一些括号和逗号。就个人而言,我更喜欢在 TSQL 中为 Web 应用程序做事,因为我可以将计算工作卸载到 SQL Server 而不是 Web Server。就我而言,我有很多数据正在为地图生成,因此不想让网络服务器陷入大量数据转换的困境。另外,为了性能,我通常在 SQL 服务器上比在 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]

我希望这能提供一些见解并帮助其他人寻找方法,祝你好运!

于 2014-08-20T19:13:19.030 回答
2

詹姆斯的回答中概述的方法效果很好。但我最近在转换经度值超过 99 的 WKT 时发现了一个错误。

我更改了正则表达式:

@"(-?\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。

于 2016-02-28T20:09:31.833 回答
1

字符串在 .net 中是不可变的,因此当您替换一些字符串时,您会创建先前字符串的编辑副本。这对于性能来说并不那么重要,就像内存使用一样。

看看JSON.net

或使用 StringBuilder 正确生成它。

StringBuilder sb = new StringBuilder();
sb.AppendFormat();
于 2011-06-28T13:04:46.637 回答
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
于 2021-05-06T10:33:18.817 回答