You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解析GeoJSON并将坐标转换为PostGIS兼容的几何格式?

将GeoJSON转换为PostGIS兼容WKT格式的高效实现方法

需求说明

需要将FeatureCollection类型的GeoJSON数据转换为PostGIS可识别的格式,提取每个Feature的几何类型(geometry.type)和坐标(geometry.coordinates),生成类似ST_GeomFromText('POLYGON((0 1, 2 5, 2 7, 0 7, 0 1))')的WKT语句。

原始GeoJSON数据如下:

{
  "type": "FeatureCollection",
  "name": "Some Boundary",
  "crs": {
    "type": "name",
    "properties": {
      "name": "urn:ogc:def:crs:OGC:1.3:CRS84"
    }
  },
  "features": [
    {
      "type": "Feature",
      "properties": {
        "State_Name": "ABC",
        "State_Code": "01"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              76.767318,
              33.228753
            ],
            [
              76.767318,
              33.228753
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "State_Name": "DEF",
        "State_Code": "02"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              79.008814,
              31.115041
            ],
            [
              79.008814,
              31.115041
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "State_Name": "GHI",
        "State_Code": "03"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              76.942524,
              30.383268
            ],
            [
              76.850815,
              30.717589
            ],
            [
              76.852673,
              30.718222
            ],
            [
              76.853471,
              30.718813
            ]
          ]
        ]
      }
    }
  ]
}

现有问题

自行编写的Java代码仅处理了简单Polygon的场景,遇到多环Polygon、MultiPolygon或其他几何类型时会失效,代码如下:

JSONObject jsonObject = (JSONObject) obj;
JSONArray features = (JSONArray) jsonObject.get("features");

JSONArray coordinates = (JSONArray) geometryObject.get("coordinates");
JSONArray coordinate = (JSONArray)  coordinates.get(0);

String geoString = "'"+str+"'((";

for(int j=0; j<coordinate.size(); j++){
    JSONArray tempArr =   (JSONArray) coordinate.get(i);
    geoString = geoString +  tempArr.get(0).toString() +" ";
    geoString =  geoString + tempArr.get(1).toString();
    int len = coordinate.size() - 1;
    if(i < len){
        geoString = geoString +",";
    }
}

geoString = geoString +  "))'";

解决方案

方案1:使用JTS GIS库(推荐)

JTS是专门处理空间数据的成熟库,能完美解析所有OGC标准的几何类型,避免手动解析的漏洞,同时支持WKT格式转换。

步骤1:引入依赖(Maven)

<dependency>
    <groupId>org.locationtech.jts</groupId>
    <artifactId>jts-core</artifactId>
    <version>1.19.0</version>
</dependency>
<dependency>
    <groupId>org.locationtech.jts.io</groupId>
    <artifactId>jts-io-common</artifactId>
    <version>1.19.0</version>
</dependency>
<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20230227</version>
</dependency>

步骤2:实现代码

import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.geojson.GeoJsonReader;
import org.json.JSONArray;
import org.json.JSONObject;

public class GeoJsonToPostgis {
    public static void main(String[] args) {
        // 替换为你的FeatureCollection JSON字符串
        String geoJsonStr = "{...}";
        JSONObject featureCollection = new JSONObject(geoJsonStr);
        JSONArray features = featureCollection.getJSONArray("features");

        GeoJsonReader geoJsonReader = new GeoJsonReader();

        for (int i = 0; i < features.length(); i++) {
            JSONObject feature = features.getJSONObject(i);
            JSONObject geometry = feature.getJSONObject("geometry");
            JSONObject properties = feature.getJSONObject("properties");
            
            try {
                // 解析GeoJSON几何为JTS对象
                Geometry geom = geoJsonReader.read(geometry.toString());
                // 转换为WKT格式
                String wkt = geom.toText();
                // 生成PostGIS兼容的语句(指定SRID=4326,对应GeoJSON的CRS84)
                String postgisGeomExpr = String.format("ST_GeomFromText('%s', 4326)", wkt);
                
                // 结合属性生成完整插入语句
                String stateName = properties.getString("State_Name");
                String stateCode = properties.getString("State_Code");
                System.out.printf("INSERT INTO boundary_table (state_name, state_code, geom) VALUES ('%s', '%s', %s);%n", 
                                  stateName, stateCode, postgisGeomExpr);
            } catch (Exception e) {
                System.err.println("处理第" + i + "个Feature失败:" + e.getMessage());
                e.printStackTrace();
            }
        }
    }
}

优势

  • 支持所有几何类型(Point、LineString、Polygon、MultiPolygon等)
  • 自动处理坐标嵌套、多环结构
  • 内置空间数据校验,避免无效几何
  • 可直接指定SRID,确保空间参考一致性

方案2:修复手动解析代码(不依赖第三方库)

如果无法引入外部库,可通过分层处理坐标嵌套、针对不同几何类型分支解析来修复代码:

import org.json.JSONArray;
import org.json.JSONObject;

public class GeoJsonToWkt {
    public static void main(String[] args) {
        String geoJsonStr = "{...}";
        JSONObject featureCollection = new JSONObject(geoJsonStr);
        JSONArray features = featureCollection.getJSONArray("features");

        for (int i = 0; i < features.length(); i++) {
            JSONObject feature = features.getJSONObject(i);
            JSONObject geometry = feature.getJSONObject("geometry");
            String geomType = geometry.getString("type");
            JSONArray coordinates = geometry.getJSONArray("coordinates");

            // 构建WKT坐标部分
            String coordSegment = buildCoordinateSegment(coordinates, geomType);
            String wkt = String.format("%s(%s)", geomType.toUpperCase(), coordSegment);
            String postgisExpr = String.format("ST_GeomFromText('%s', 4326)", wkt);

            // 输出插入语句
            String stateName = feature.getJSONObject("properties").getString("State_Name");
            System.out.printf("INSERT INTO boundary_table (state_name, geom) VALUES ('%s', %s);%n", stateName, postgisExpr);
        }
    }

    private static String buildCoordinateSegment(JSONArray coordinates, String geomType) {
        StringBuilder sb = new StringBuilder();
        switch (geomType) {
            case "Point":
                sb.append(coordinates.getDouble(0)).append(" ").append(coordinates.getDouble(1));
                break;
            case "LineString":
                sb.append("(");
                appendCoordPairs(coordinates, sb);
                sb.append(")");
                break;
            case "Polygon":
                sb.append("(");
                for (int i = 0; i < coordinates.length(); i++) {
                    if (i > 0) sb.append(",");
                    sb.append("(");
                    appendCoordPairs(coordinates.getJSONArray(i), sb);
                    sb.append(")");
                }
                sb.append(")");
                break;
            case "MultiPolygon":
                sb.append("(");
                for (int i = 0; i < coordinates.length(); i++) {
                    if (i > 0) sb.append(",");
                    sb.append("(");
                    JSONArray polygonRings = coordinates.getJSONArray(i);
                    for (int j = 0; j < polygonRings.length(); j++) {
                        if (j > 0) sb.append(",");
                        sb.append("(");
                        appendCoordPairs(polygonRings.getJSONArray(j), sb);
                        sb.append(")");
                    }
                    sb.append(")");
                }
                sb.append(")");
                break;
            // 可扩展支持MultiPoint、MultiLineString等类型
        }
        return sb.toString();
    }

    private static void appendCoordPairs(JSONArray coordPairs, StringBuilder sb) {
        for (int i = 0; i < coordPairs.length(); i++) {
            if (i > 0) sb.append(",");
            JSONArray pair = coordPairs.getJSONArray(i);
            sb.append(pair.getDouble(0)).append(" ").append(pair.getDouble(1));
        }
    }
}

改进点

  • 针对不同几何类型做分支处理,覆盖常见场景
  • 分层处理坐标嵌套,支持多环Polygon和MultiPolygon
  • 使用StringBuilder提升字符串拼接效率
  • 修复了原代码中循环变量混用的错误

内容的提问来源于stack exchange,提问作者David

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 19:35:22