news 2026/10/12 4:36:32

GDAL ESRIJSON / FeatureService 驱动:读取 ArcGIS REST 数据的分页滚动、字段映射与类型转换详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
GDAL ESRIJSON / FeatureService 驱动:读取 ArcGIS REST 数据的分页滚动、字段映射与类型转换详解
  • GIS
  • 遥感
  • 数据工程

【免费下载链接】gdal

GDAL is an open source MIT licensed translator library for raster and vector geospatial data formats.

项目地址:https://gitcode.com/gh_mirrors/gd/gdal
点击查看免费下载

GDAL 的ESRIJSON驱动可以直接读取符合 GeoServices REST 规范的 Feature Service 请求结果(典型实现为 ArcGIS Server REST API),并支持对跨多页的大结果集进行自动滚动读取。本文基于 GDAL 仓库中的驱动文档与源码实现,系统讲解该驱动的数据源类型、分页机制(resultOffset/resultRecordCount、FEATURE_SERVER_PAGING)、HTTP_METHOD打开选项、ESRI 字段类型到 OGR 的类型映射,以及 ESRI JSON 几何的解析规则,帮助你在命令行与编程接口中可靠地消费 ArcGIS 服务输出。

一、驱动定位与能力概览

该驱动的核心用途是读取 Feature Service 请求返回的 JSON 数据,遵循 GeoServices REST Specification,兼容 ArcGIS Server REST API 的输出格式。当结果集较大、被服务器切分到多个分页(ArcGIS Server >= 10.3)时,驱动可以自动滚动读取全部页面。

分页的启用规则(来自 驱动文档):

  • 若打开的 URL不包含显式resultOffset参数,滚动读取自动启用;
  • 若 URL包含resultOffset但仍希望滚动,必须将打开选项FEATURE_SERVER_PAGING设为YES;
  • 页大小可用resultRecordCount参数显式指定(受服务器上限约束);若不设置,OGR 会自动设置为服务器允许的最大值。

文档中特别强调的实操要点:分页请求要可靠工作,通常需要为某个字段加上排序子句——通常是OBJECTID,即在 URL 中添加&orderByFields=OBJECTID+ASC参数,保证服务器按确定顺序返回结果,避免滚动读取时遗漏或重复要素。

驱动注册元数据(见 ogresrijsondriver.cpp)声明了其能力:

  • 矢量驱动(GDAL_DCAP_VECTOR=YES);
  • 支持 Z 与 M 几何(GDAL_DCAP_Z_GEOMETRIES=YES、GDAL_DCAP_MEASURED_GEOMETRIES=YES);
  • 支持虚拟 I/O(GDAL_DCAP_VIRTUALIO=YES),因此/vsimem/等虚拟文件路径也可作为数据源;
  • 支持OGRSQL与SQLITE两种 SQL 方言(GDAL_DMD_SUPPORTED_SQL_DIALECTS),可以对读入的 FeatureCollection 执行 SQL 过滤。

二、三类数据源与 ESRIJSON: 前缀

驱动接受三种数据源:

  1. URL——向 Web 服务发起 HTTP 请求;
  2. 纯文本 ESRIJSON 文件——以.json扩展名识别;
  3. 直接传入的 ESRI JSON 文本——例如通过ogr.Open(text)或OGRSFDriverOpen直接传入字符串。

为消除与其他驱动(尤其是GeoJSON)的歧义,URL/文件名/文本前都可以加ESRIJSON:前缀。此外,自 GDAL 3.10 起,对支持该选项的命令行工具指定-if ESRIJSON,或在GDALOpenEx中将papszAllowedDrivers设为仅含ESRIJSON,也会强制驱动识别传入的 URL/文件名/文本。

这一行为在源码OGRESRIJSONDriverIdentify()中可以直接印证(ogresrijsondriver.cpp):当数据源被判定为 Web 服务类型时,要么是唯一允许的ESRIJSON驱动(IsSingleAllowedDriver("ESRIJSON")),要么文件名必须(不区分大小写)以ESRIJSON:开头,否则返回"不确定",让其他驱动(如GeoJSON)竞争识别。

三、打开选项:FEATURE_SERVER_PAGING 与 HTTP_METHOD

3.1 FEATURE_SERVER_PAGING

选项取值说明
FEATURE_SERVER_PAGINGYES、NO是否自动滚动读取 ArcGIS Feature Service 端点的结果。仅对 ArcGIS Server >= 10.3 且图层具备supportsPagination=true能力时生效

3.2 HTTP_METHOD(GDAL 3.13 起)

选项取值默认说明
HTTP_METHODAUTO、GET、POSTAUTO向服务器发送请求使用的 HTTP 方法。AUTO模式下使用 GET,除非 URL 长度超过 256 字符;此时?之后的查询参数会被移到 POST 请求体中发送

从源码看,这两个选项都在驱动注册时通过GDAL_DMD_OPENOPTIONLIST元数据声明(ogresrijsondriver.cpp)。HTTP_METHOD的实际执行逻辑在 GeoJSON 家族共享的 HTTP 获取函数中(ogrgeojsonutils.cpp):

  • 定义常量MAX_URL_LEN_FOR_GET = 256;
  • AUTO模式下:URL 短于 256 字符走 GET,否则自动改为 POST;
  • POST 模式下:把?之后的查询串取出,塞入POSTFIELDS请求选项,URL 本体只保留到?为止。

这意味着当你的 Feature Service 查询 URL 很长(例如带复杂的where过滤表达式)时,无需手工干预,驱动会自动降级为 POST,规避部分服务器对 URL 长度的限制。

四、分页滚动的底层实现

FEATURE_SERVER_PAGING的判定与 URL 中resultOffset的交互逻辑位于OGRGeoJSONDriverOpenInternal()(ogrgeojsondriver.cpp)。核心条件是:数据源报告存在后续页(HasOtherPages()),且文件名以http开头或位于/vsimem/之下,然后按以下布尔表达式决定是否用OGRESRIFeatureServiceDataset包装数据源:

(无 resultOffset 且 FEATURE_SERVER_PAGING 未显式设为 NO) 或 (有 resultOffset 且 FEATURE_SERVER_PAGING 显式设为 YES)

OGRESRIFeatureServiceDataset的构造与滚动逻辑(ogrgeojsondriver.cpp)包含三个值得注意的细节:

  1. 页大小的自动确定:若 URL 中未显式指定resultRecordCount,驱动假设"服务器在首请求中返回的要素数就是其允许的最大页大小",并把这个值回填到 URL 中用于后续请求;若用户显式指定的resultRecordCount大于实际返回条数,则发出警告:Specified resultRecordCount=%d is greater than the maximum %d supported by the server。
  2. 滚动推进:LoadNextPage()将resultOffset增加当前页的要素数,然后调用LoadPage(),后者用CPLURLAddKVP()把新的resultOffset拼进 URL,重新打开并解析新一页;
  3. 复位行为:MyResetReading()在已滚动过(m_nLastOffset > m_nFirstOffset)时会把偏移量拉回起始位置并重新加载首页,保证ResetReading()语义正确。

自动化测试用/vsimem虚拟文件完整覆盖了这一滚动路径(autotest/ogr/ogr_esrijson.py):先在内存中放置带"exceededTransferLimit": true的第一页,再放置resultOffset=1的第二页,验证GetNextFeature()能跨页依次取到 FID 1、20 两个要素;同时测试了returnCountOnly=true对应的快速GetFeatureCount()(返回{"count": 123456}),以及returnExtentOnly=true&f=geojson请求中解析bbox成员来快速获得图层范围的行为。

五、ESRI 字段类型到 OGR 的映射

OGRESRIJSONReader::ParseField()(ogresrijsonreader.cpp)负责解析响应中的fields数组并生成图层定义。ESRI 类型与 OGR 类型的映射表(源码 ogresrijsonreader.cpp)如下:

ESRI 字段类型OGR 类型OGR 子类型
esriFieldTypeStringOFTString无
esriFieldTypeSingleOFTRealOFSTFloat32
esriFieldTypeDoubleOFTReal无
esriFieldTypeSmallIntegerOFTIntegerOFSTInt16
esriFieldTypeIntegerOFTInteger无
esriFieldTypeDateOFTDateTime无
esriFieldTypeDateOnlyOFTDate无
esriFieldTypeTimeOnlyOFTTime无
esriFieldTypeBigIntegerOFTInteger64无
esriFieldTypeGUIDOFTStringOFSTUUID
esriFieldTypeGlobalIDOFTStringOFSTUUID

几个值得留意的处理细节:

  • OID 特殊处理:遇到esriFieldTypeOID类型时,除映射为OFTInteger外,还会调用poLayer_->SetFIDColumn(pszObjName),把该字段设为要素 FID 列,后续要素的 FID 直接取自attributes中该字段的值(ogresrijsonreader.cpp);
  • 宽度处理:读取length成员作为字段宽度;若宽度为INT_MAX(2147483647),源码注释指出这是"字段宽度未知"的占位值,此时不设置宽度,更符合 OGR 对 0 宽度(无限制)的表达;
  • 别名:alias成员若与字段名不同,会被设为 OGR 的 alternative name;
  • 日期换算:ESRI 日期是毫秒级 Unix 时间戳,EsriDateToOGRDate()将其拆解为年月日时分秒并写入OGRField(秒为 float 以容纳毫秒余数),ogresrijsonreader.cpp。

若响应中没有fields数组(某些简化的 FeatureCollection 不提供),驱动会退而求其次:先尝试fieldAliases对象;再不行则遍历各要素的attributes,按实际出现顺序推断字段名、类型与层级(嵌套属性用.分隔展平),并利用有向无环图对字段做拓扑排序,保证跨要素字段顺序稳定(ogresrijsonreader.cpp)。

六、ESRI JSON 几何格式

ESRI JSON 的几何表示与 GeoJSON 不同:点用x/y(可选z)对象,多边形用rings(带方向约定)而非 GeoJSON 的嵌套坐标数组,点集用points数组。解析入口在 ogresrijsongeometry.cpp:

  • OGRESRIJSONGetGeometryType()(ogresrijsongeometry.cpp)根据顶层键(x/y、rings、points等)推断几何类型;
  • 多边形按rings成员读取,缺失或类型错误时报告Missing 'rings' member/Invalid 'rings' member;
  • 空间参考优先取几何内部的spatialReference对象(支持wkt、latestWkt等键,测试用例test_ogr_esrijson_identify_srs即验证了从spatialReference.wkt解析出 EPSG:4326,见 autotest/ogr/ogr_esrijson.py)。

驱动在ReadLayers()中的几何类型推断策略(ogresrijsonreader.cpp)是:先用OGRESRIJSONGetGeometryType()判断整体;若为wkbNone但存在 SRS,则置为wkbUnknown;否则逐个检查features中首个带geometry成员的要素来推断,并把该几何内的spatialReference作为图层 SRS。

geometry为null的要素(测试数据中的resultOffset1即如此)会被读取为无几何的要素,不会中断滚动。测试test_ogr_esrijson_create_geometry_from_esri_json还验证了 Python 接口ogr.CreateGeometryFromEsriJson('{ "x": 2, "y": 49 }')可直接构造POINT (2 49)。

七、命令示例

文档给出的标准示例——读取一个不支持分页的 Feature Service 查询结果(驱动文档):

ogrinfo -ro -al "https://sampleserver6.arcgisonline.com/arcgis/rest/services/PoolPermits/FeatureServer/0/query?resultRecordCount=10&f=pjson"

结合本文说明,一个针对支持分页(supportsPagination=true)的 ArcGIS 10.3+ 服务的更完整写法示例如下(命令格式以当前仓库文档为准,服务地址请替换为实际环境):

# 自动分页滚动:URL 不含 resultOffset,并加稳定排序 ogrinfo -ro -al "https://your.server/arcgis/rest/services/Svc/FeatureServer/0/query?where=1=1&orderByFields=OBJECTID+ASC&f=pjson" # URL 已含 resultOffset 时,用打开选项强制开启滚动 ogrinfo -ro -openoption FEATURE_SERVER_PAGING=YES -al \ "https://your.server/.../query?resultOffset=0&f=pjson" # 强制 POST 请求方法 ogrinfo -ro -openoption HTTP_METHOD=POST -al "https://your.server/.../query?where=..."

测试中还展示了ogr.Open()直接打开/vsimem/下带查询参数 URL 的用法,以及直接ogr.Open(json_text)打开 ESRIJSON 文本(要求文本以 ESRI 特征字段开头),可作为编程接口参照(autotest/ogr/ogr_esrijson.py)。

八、小结

  • ESRIJSON驱动同时覆盖 URL、.json文件与直接文本三类数据源,配合ESRIJSON:前缀、-if ESRIJSON或papszAllowedDrivers可消除与GeoJSON驱动的识别歧义;
  • 分页滚动默认自动启用(URL 无resultOffset时),FEATURE_SERVER_PAGING=YES用于在含resultOffset的 URL 上强制滚动,页大小由resultRecordCount控制并在缺省时取服务器允许的最大值;滚动依赖orderByFields保证顺序稳定性;
  • HTTP_METHOD(GDAL 3.13 起)在 AUTO 模式下按 256 字符阈值自动在 GET/POST 间切换,长 URL 的查询参数自动移入 POST 体;
  • 字段类型经goMapEsriTypeToOGR映射表精确转换为 OGR 类型(含 Float32、Int16、UUID 子类型),OID 字段自动成为 FID 列,毫秒时间戳自动换算为 OGR 日期时间;
  • 几何支持x/y、rings、points等 ESRI 原生表示,SRS 可从顶层或几何内嵌spatialReference解析。

相关入口文件与测试:驱动注册、FeatureService 滚动数据集、响应解析、几何解析、自动化测试、测试数据。

  • GIS
  • 遥感
  • 数据工程

【免费下载链接】gdal

GDAL is an open source MIT licensed translator library for raster and vector geospatial data formats.

项目地址:https://gitcode.com/gh_mirrors/gd/gdal
点击查看免费下载

相关推荐

上一篇:智能音乐转录神器:5分钟将钢琴音频变乐谱的终极指南
下一篇:Zabbix Proxy 健康监控模板全解析:本地、远程与 Agent 采集三种方案实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/12 4:36:30

WOA优化LSTM超参数:多输入分类预测的MATLAB完整实现

做过多输入分类预测的朋友应该都有过这种感受:数据集准备好了,模型结构也敲定了,最后卡在LSTM那几个超参数上——隐藏层节点取多少、学习率定多大、正则化系数怎么设,靠感觉拍脑袋真的太费时间。前阵子我在一个多传感器状态分类任…

作者头像 李华
网站建设 2026/10/12 4:33:26

测试面试现场:优雅排查Bug的五步定位法实战

测试面试官把笔记本电脑屏幕转过来的那一刻,我就知道接下来的话题要变了。屏幕上要么是一段代码,要么是一张线上报错日志的截图,紧跟着大概率是这么一句话——“这个Bug,如果现在出现在线上,你准备怎么排查&#xff1f…

作者头像 李华
网站建设 2026/10/12 4:32:25

零基础AI漫剧量产全流程:从工具选型到避坑指南

刚才在创作营里,老师让我们写下“你印象最深的动态漫画面”,然后把它丢进AI工具里跑了一版,看到成片的那一刻,我突然意识到:以前需要一整个动画团队才能做的漫剧,现在一个人、一台普通电脑、一堆订阅工具就…

作者头像 李华