第06章 - 数据格式转换
第06章 - 数据格式转换
6.1 格式支持概述
6.1.1 支持的格式
geometry-api-java 支持多种空间数据格式的导入和导出:
| 格式 | 导入 | 导出 | 说明 |
|---|---|---|---|
| JSON | ✅ | ✅ | Esri JSON 格式 |
| GeoJSON | ✅ | ✅ | OGC GeoJSON 格式 |
| WKT | ✅ | ✅ | Well-Known Text |
| WKB | ✅ | ✅ | Well-Known Binary |
| ESRI Shape | ✅ | ✅ | Shapefile 二进制格式 |
6.1.2 格式转换算子
每种格式都有对应的导入和导出算子:
// JSON
OperatorImportFromJson / OperatorExportToJson
// GeoJSON
OperatorImportFromGeoJson / OperatorExportToGeoJson
// WKT
OperatorImportFromWkt / OperatorExportToWkt
// WKB
OperatorImportFromWkb / OperatorExportToWkb
// ESRI Shape
OperatorImportFromESRIShape / OperatorExportToESRIShape
6.2 Esri JSON 格式
6.2.1 JSON 格式规范
Esri JSON 是 ArcGIS 使用的 JSON 几何格式:
// Point
{"x": 116.4, "y": 39.9}
// Point with Z and M
{"x": 116.4, "y": 39.9, "z": 100, "m": 1.5}
// Polyline
{
"paths": [
[[0, 0], [10, 10], [20, 0]],
[[30, 30], [40, 40]]
]
}
// Polygon
{
"rings": [
[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]],
[[2, 2], [2, 8], [8, 8], [8, 2], [2, 2]]
]
}
// MultiPoint
{
"points": [[0, 0], [10, 10], [20, 20]]
}
// With Spatial Reference
{
"x": 116.4,
"y": 39.9,
"spatialReference": {"wkid": 4326}
}
6.2.2 导入 JSON
// 从 JSON 字符串导入
String json = "{\"x\": 116.4, \"y\": 39.9}";
// 方式一:使用 GeometryEngine
MapGeometry mapGeom = GeometryEngine.jsonToGeometry(json);
Geometry geometry = mapGeom.getGeometry();
SpatialReference sr = mapGeom.getSpatialReference();
// 方式二:使用 Operator
OperatorImportFromJson op = OperatorImportFromJson.local();
MapGeometry result = op.execute(Geometry.Type.Unknown, json);
6.2.3 导出 JSON
Point point = new Point(116.4, 39.9);
SpatialReference sr = SpatialReference.create(4326);
// 方式一:使用 GeometryEngine
String json = GeometryEngine.geometryToJson(sr, point);
// 方式二:使用 Operator
OperatorExportToJson op = OperatorExportToJson.local();
String json2 = op.execute(sr, point);
System.out.println(json);
// {"x":116.4,"y":39.9,"spatialReference":{"wkid":4326}}
6.2.4 批量转换
// 批量导出
Geometry[] geometries = {point1, line1, polygon1};
SimpleGeometryCursor cursor = new SimpleGeometryCursor(geometries);
OperatorExportToJson op = OperatorExportToJson.local();
JsonCursor jsonCursor = op.execute(sr, cursor);
String json;
while ((json = jsonCursor.next()) != null) {
System.out.println(json);
}
6.3 GeoJSON 格式
6.3.1 GeoJSON 格式规范
GeoJSON 是 OGC 标准的 JSON 格式:
// Point
{
"type": "Point",
"coordinates": [116.4, 39.9]
}
// LineString
{
"type": "LineString",
"coordinates": [[0, 0], [10, 10], [20, 0]]
}
// Polygon
{
"type": "Polygon",
"coordinates": [
[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]],
[[2, 2], [2, 8], [8, 8], [8, 2], [2, 2]]
]
}
// MultiPoint
{
"type": "MultiPoint",
"coordinates": [[0, 0], [10, 10]]
}
// GeometryCollection
{
"type": "GeometryCollection",
"geometries": [
{"type": "Point", "coordinates": [0, 0]},
{"type": "LineString", "coordinates": [[0, 0], [10, 10]]}
]
}
6.3.2 导入 GeoJSON
String geoJson = "{\"type\": \"Point\", \"coordinates\": [116.4, 39.9]}";
// 方式一:使用 GeometryEngine
MapGeometry mapGeom = GeometryEngine.geoJsonToGeometry(
geoJson, 0, Geometry.Type.Unknown);
Geometry geometry = mapGeom.getGeometry();
// 方式二:使用 Operator
OperatorImportFromGeoJson op = OperatorImportFromGeoJson.local();
MapGeometry result = op.execute(0, Geometry.Type.Unknown, geoJson, null);
6.3.3 导出 GeoJSON
Point point = new Point(116.4, 39.9);
SpatialReference sr = SpatialReference.create(4326);
// 方式一:使用 GeometryEngine(不带空间参考)
String geoJson = GeometryEngine.geometryToGeoJson(point);
// 方式二:使用 GeometryEngine(带空间参考)
String geoJson2 = GeometryEngine.geometryToGeoJson(sr, point);
// 方式三:使用 Operator
OperatorExportToGeoJson op = OperatorExportToGeoJson.local();
String geoJson3 = op.execute(sr, point);
6.3.4 GeoJSON 导入/导出标志
// GeoJsonImportFlags
int IMPORT_FLAGS = GeoJsonImportFlags.geoJsonImportDefaults;
// geoJsonImportDefaults = 0
// geoJsonImportNonTrusted = 2 // 不信任输入,进行验证
// GeoJsonExportFlags
int EXPORT_FLAGS = GeoJsonExportFlags.geoJsonExportDefaults;
// geoJsonExportDefaults = 0
// geoJsonExportPreferMultiGeometry = 1 // 优先输出 Multi* 类型
6.3.5 处理 FeatureCollection
// GeoJSON FeatureCollection 需要先解析
String featureCollectionJson = "{ \"type\": \"FeatureCollection\", ...}";
// 使用 Jackson 或其他 JSON 库解析
// 然后提取 geometry 字段进行处理
// 示例:使用 OGC API
import com.esri.core.geometry.ogc.*;
String pointGeoJson = "{\"type\": \"Point\", \"coordinates\": [116.4, 39.9]}";
OGCGeometry ogcGeom = OGCGeometry.fromGeoJson(pointGeoJson);
Geometry esriGeom = ogcGeom.getEsriGeometry();
6.4 WKT 格式
6.4.1 WKT 格式规范
Well-Known Text (WKT) 是一种文本格式:
POINT (116.4 39.9)
POINT Z (116.4 39.9 100)
POINT M (116.4 39.9 50)
POINT ZM (116.4 39.9 100 50)
LINESTRING (0 0, 10 10, 20 0)
LINESTRING EMPTY
POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))
POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (2 2, 2 8, 8 8, 8 2, 2 2))
MULTIPOINT ((0 0), (10 10))
MULTILINESTRING ((0 0, 10 10), (20 20, 30 30))
MULTIPOLYGON (((0 0, 10 0, 10 10, 0 10, 0 0)))
GEOMETRYCOLLECTION (POINT (0 0), LINESTRING (0 0, 10 10))
6.4.2 导入 WKT
String wkt = "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))";
// 方式一:使用 GeometryEngine
Geometry geometry = GeometryEngine.geometryFromWkt(
wkt,
WktImportFlags.wktImportDefaults,
Geometry.Type.Unknown
);
// 方式二:使用 Operator
OperatorImportFromWkt op = OperatorImportFromWkt.local();
Geometry result = op.execute(0, Geometry.Type.Unknown, wkt, null);
6.4.3 导出 WKT
Polygon polygon = createPolygon();
// 方式一:使用 GeometryEngine
String wkt = GeometryEngine.geometryToWkt(polygon, WktExportFlags.wktExportDefaults);
// 方式二:使用 Operator
OperatorExportToWkt op = OperatorExportToWkt.local();
String wkt2 = op.execute(0, polygon, null);
System.out.println(wkt);
// POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))
6.4.4 WKT 导入/导出标志
// WktImportFlags
int flags = WktImportFlags.wktImportDefaults; // 默认
int flags2 = WktImportFlags.wktImportNonTrusted; // 不信任输入
// WktExportFlags
int exportFlags = WktExportFlags.wktExportDefaults; // 默认
int exportFlags2 = WktExportFlags.wktExportMultiPoint; // 导出为 MULTIPOINT
int exportFlags3 = WktExportFlags.wktExportLineString; // 导出为 LINESTRING
int exportFlags4 = WktExportFlags.wktExportPolygon; // 导出为 POLYGON
int exportFlags5 = WktExportFlags.wktExportPoint; // 导出为 POINT
6.4.5 处理带 Z/M 的 WKT
// 导入带 Z 的 WKT
String wktZ = "POINT Z (116.4 39.9 100)";
Geometry geom = GeometryEngine.geometryFromWkt(wktZ, 0, Geometry.Type.Unknown);
Point point = (Point) geom;
System.out.println("Z 值: " + point.getZ());
// 导入带 M 的 WKT
String wktM = "POINT M (116.4 39.9 50.5)";
Geometry geomM = GeometryEngine.geometryFromWkt(wktM, 0, Geometry.Type.Unknown);
// 导入带 ZM 的 WKT
String wktZM = "POINT ZM (116.4 39.9 100 50.5)";
Geometry geomZM = GeometryEngine.geometryFromWkt(wktZM, 0, Geometry.Type.Unknown);
6.5 WKB 格式
6.5.1 WKB 格式概述
Well-Known Binary (WKB) 是 WKT 的二进制版本,用于高效存储和传输:
结构:
[字节序(1字节)] [几何类型(4字节)] [坐标数据...]
字节序:
01 = 小端序 (Little Endian)
00 = 大端序 (Big Endian)
几何类型:
1 = Point
2 = LineString
3 = Polygon
4 = MultiPoint
5 = MultiLineString
6 = MultiPolygon
7 = GeometryCollection
6.5.2 导入 WKB
byte[] wkbBytes = getWkbData();
ByteBuffer wkb = ByteBuffer.wrap(wkbBytes);
// 方式一:使用 Operator
OperatorImportFromWkb op = OperatorImportFromWkb.local();
Geometry geometry = op.execute(0, Geometry.Type.Unknown, wkb, null);
// 支持 OGC 结构
OGCStructure ogcStructure = op.executeOGC(0, wkb, null);
6.5.3 导出 WKB
Polygon polygon = createPolygon();
// 方式一:使用 Operator
OperatorExportToWkb op = OperatorExportToWkb.local();
ByteBuffer wkb = op.execute(0, polygon, null);
// 转换为字节数组
byte[] bytes = new byte[wkb.remaining()];
wkb.get(bytes);
6.5.4 WKB 字节序
// 设置字节序
int flags = WkbExportFlags.wkbExportDefaults; // 默认(大端序)
int flagsLE = WkbExportFlags.wkbExportLittleEndian; // 小端序
ByteBuffer wkbLE = OperatorExportToWkb.local().execute(
WkbExportFlags.wkbExportLittleEndian,
geometry,
null
);
6.5.5 WKB 与数据库集成
// PostGIS 通常使用 WKB 格式
// 从 ResultSet 读取 WKB
ResultSet rs = stmt.executeQuery("SELECT ST_AsBinary(geom) FROM table");
while (rs.next()) {
byte[] wkb = rs.getBytes(1);
ByteBuffer buffer = ByteBuffer.wrap(wkb);
Geometry geom = OperatorImportFromWkb.local()
.execute(0, Geometry.Type.Unknown, buffer, null);
}
// 将 WKB 写入数据库
ByteBuffer wkb = OperatorExportToWkb.local().execute(0, geometry, null);
pstmt.setBytes(1, wkb.array());
6.6 ESRI Shape 格式
6.6.1 Shape 格式概述
ESRI Shape 格式是 Shapefile 中存储几何的二进制格式:
结构:
[ShapeType(4字节)] [BoundingBox(32字节)] [Parts...] [Points...]
6.6.2 导入 Shape
byte[] shapeBytes = getShapeData();
// 使用 GeometryEngine
Geometry geometry = GeometryEngine.geometryFromEsriShape(
shapeBytes,
Geometry.Type.Unknown
);
// 使用 Operator
OperatorImportFromESRIShape op = OperatorImportFromESRIShape.local();
ByteBuffer buffer = ByteBuffer.wrap(shapeBytes);
buffer.order(ByteOrder.LITTLE_ENDIAN);
Geometry result = op.execute(0, Geometry.Type.Unknown, buffer);
6.6.3 导出 Shape
Polygon polygon = createPolygon();
// 使用 GeometryEngine
byte[] shapeBytes = GeometryEngine.geometryToEsriShape(polygon);
// 使用 Operator
OperatorExportToESRIShape op = OperatorExportToESRIShape.local();
ByteBuffer buffer = op.execute(0, polygon);
6.6.4 Shape 导入/导出标志
// ShapeImportFlags
int flags = ShapeImportFlags.ShapeImportDefaults; // 默认
int flags2 = ShapeImportFlags.ShapeImportNonTrusted; // 不信任输入
// ShapeExportFlags
int exportFlags = ShapeExportFlags.ShapeExportDefaults; // 默认
6.7 格式转换实战
6.7.1 WKT 转 GeoJSON
public String wktToGeoJson(String wkt) {
Geometry geometry = GeometryEngine.geometryFromWkt(
wkt, 0, Geometry.Type.Unknown);
return GeometryEngine.geometryToGeoJson(geometry);
}
// 使用
String wkt = "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))";
String geoJson = wktToGeoJson(wkt);
6.7.2 GeoJSON 转 WKT
public String geoJsonToWkt(String geoJson) {
MapGeometry mapGeom = GeometryEngine.geoJsonToGeometry(
geoJson, 0, Geometry.Type.Unknown);
return GeometryEngine.geometryToWkt(mapGeom.getGeometry(), 0);
}
// 使用
String geoJson = "{\"type\": \"Point\", \"coordinates\": [116.4, 39.9]}";
String wkt = geoJsonToWkt(geoJson);
// 结果: POINT (116.4 39.9)
6.7.3 批量格式转换
/**
* 批量将 WKT 转换为 GeoJSON
*/
public List<String> batchWktToGeoJson(List<String> wktList) {
List<String> results = new ArrayList<>();
OperatorImportFromWkt importOp = OperatorImportFromWkt.local();
OperatorExportToGeoJson exportOp = OperatorExportToGeoJson.local();
for (String wkt : wktList) {
Geometry geom = importOp.execute(0, Geometry.Type.Unknown, wkt, null);
String geoJson = exportOp.execute(null, geom);
results.add(geoJson);
}
return results;
}
6.7.4 格式转换工具类
public class GeometryFormatConverter {
public static Geometry fromWkt(String wkt) {
return GeometryEngine.geometryFromWkt(wkt, 0, Geometry.Type.Unknown);
}
public static String toWkt(Geometry geometry) {
return GeometryEngine.geometryToWkt(geometry, 0);
}
public static Geometry fromGeoJson(String geoJson) {
MapGeometry mg = GeometryEngine.geoJsonToGeometry(
geoJson, 0, Geometry.Type.Unknown);
return mg.getGeometry();
}
public static String toGeoJson(Geometry geometry) {
return GeometryEngine.geometryToGeoJson(geometry);
}
public static Geometry fromWkb(byte[] wkb) {
ByteBuffer buffer = ByteBuffer.wrap(wkb);
return OperatorImportFromWkb.local()
.execute(0, Geometry.Type.Unknown, buffer, null);
}
public static byte[] toWkb(Geometry geometry) {
ByteBuffer buffer = OperatorExportToWkb.local()
.execute(0, geometry, null);
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
return bytes;
}
public static Geometry fromJson(String json) {
MapGeometry mg = GeometryEngine.jsonToGeometry(json);
return mg.getGeometry();
}
public static String toJson(Geometry geometry, SpatialReference sr) {
return GeometryEngine.geometryToJson(sr, geometry);
}
}
6.8 处理复杂几何
6.8.1 GeometryCollection 处理
// 导入 GeometryCollection
String wkt = "GEOMETRYCOLLECTION (POINT (0 0), LINESTRING (0 0, 10 10))";
// 使用 OGC API 处理
OGCGeometry ogcGeom = OGCGeometry.fromText(wkt);
if (ogcGeom instanceof OGCConcreteGeometryCollection) {
OGCConcreteGeometryCollection collection =
(OGCConcreteGeometryCollection) ogcGeom;
int numGeoms = collection.numGeometries();
for (int i = 0; i < numGeoms; i++) {
OGCGeometry geom = collection.geometryN(i);
System.out.println(geom.geometryType());
}
}
6.8.2 多部分几何
// MultiPolygon WKT
String multiPolygonWkt = "MULTIPOLYGON (((0 0, 10 0, 10 10, 0 10, 0 0)), " +
"((20 20, 30 20, 30 30, 20 30, 20 20)))";
Geometry geom = GeometryEngine.geometryFromWkt(
multiPolygonWkt, 0, Geometry.Type.Unknown);
// 在 ESRI 几何中,MultiPolygon 表示为单个 Polygon 多个环
Polygon polygon = (Polygon) geom;
int pathCount = polygon.getPathCount();
System.out.println("环数量: " + pathCount);
6.9 错误处理
6.9.1 格式解析错误
public Geometry safeParseWkt(String wkt) {
try {
return GeometryEngine.geometryFromWkt(wkt, 0, Geometry.Type.Unknown);
} catch (IllegalArgumentException e) {
System.err.println("WKT 解析错误: " + e.getMessage());
return null;
} catch (GeometryException e) {
System.err.println("几何错误: " + e.getMessage());
return null;
}
}
public Geometry safeParseGeoJson(String geoJson) {
try {
MapGeometry mg = GeometryEngine.geoJsonToGeometry(
geoJson, 0, Geometry.Type.Unknown);
return mg.getGeometry();
} catch (Exception e) {
System.err.println("GeoJSON 解析错误: " + e.getMessage());
return null;
}
}
6.9.2 验证几何
public boolean isValidGeometry(Geometry geometry, SpatialReference sr) {
if (geometry == null || geometry.isEmpty()) {
return false;
}
// 检查是否简单
OperatorSimplify op = OperatorSimplify.local();
NonSimpleResult result = new NonSimpleResult();
boolean isSimple = op.isSimpleAsFeature(geometry, sr, true, result, null);
if (!isSimple) {
System.err.println("几何不简单: " + result.m_reason);
return false;
}
return true;
}
6.10 本章小结
本章详细介绍了 geometry-api-java 的数据格式转换:
- JSON 格式:Esri JSON,带空间参考
- GeoJSON 格式:OGC 标准格式
- WKT 格式:文本格式,支持 Z/M
- WKB 格式:二进制格式,适合数据库存储
- Shape 格式:Shapefile 几何格式
- 格式转换:相互转换的方法
- 复杂几何:GeometryCollection 处理
- 错误处理:解析和验证
最佳实践:
- 根据场景选择合适格式
- 使用工具类封装转换逻辑
- 处理可能的解析错误
- 验证输入几何的有效性

浙公网安备 33010602011771号