Openlayers+GeoServer+MySql获得JSON、GML数据的兼容性问题

问题

在使用OpenLayers4获得GeoServer数据时出现的一个问题:

if (currentSource.getGetFeatureInfoUrl) {
                    url = currentSource.getGetFeatureInfoUrl(evt.coordinate, viewResolution, viewProjection, {
                        'INFO_FORMAT': 'application/json'//vnd.ogc.gml
                    });

                    //向服务器发送请求,获得返回数据
                    $.get(url, function (data) {
                        var geoJSONReader = new ol.format.GeoJSON();
                        var feature = geoJSONReader.readFeatures(data)[0];

......

GeoServer连接的MySql数据库,空间数据包含Date类型的属性(如:’2017-11-2′)。

获得的feature的Date属性产生了错误:’2017-11-2Z‘,多了一个Z

经过检查,发现get到的data中已经产生了该错误。

分析问题过程

既然json格式对Date的支持不好,那就改变数据格式。查询GeoServer官网,发现getFeatureInfo方法支持的格式有:

经过测试GML2支持Date类型数据(GML3出现同样的错误)。因此改为使用GML2:

 

if (currentSource.getGetFeatureInfoUrl) {
                    url = currentSource.getGetFeatureInfoUrl(evt.coordinate, viewResolution, viewProjection, {
                        'INFO_FORMAT': 'application/vnd.ogc.gml'//vnd.ogc.gml
                    });

                    //向服务器发送请求,获得返回数据
                    $.get(url, function (data) {
                        var gml2Reader = new ol.format.GML2();
                        var feature = gml2Reader.readFeatures(data)[0];

......

获取的data没有问题,但是经过ol.format.GML2解析后的feature出现了经纬度颠倒的情况:

查看OL4中有关ol.format.GML2读取数据的源码:

https://github.com/openlayers/openlayers/blob/2eea8df75af5f548cad4e8e0d0597e487d90a06b/src/ol/format/gml2.js#L59
https://github.com/openlayers/openlayers/blob/2eea8df75af5f548cad4e8e0d0597e487d90a06b/src/ol/format/gml2.js#L59
ol.format.GML2.prototype.readFlatCoordinates_ = function(node, objectStack) {
ol.format.GML2.prototype.readFlatCoordinates_ = function(node, objectStack) {
ol.format.GML2.prototype.readFlatCoordinates_ = function(node, objectStack) {
  var s = ol.xml.getAllTextContent(node, false).replace(/^\s*|\s*$/g, '');
  var context = /** @type {ol.XmlNodeStackItem} */ (objectStack[0]);
  var containerSrs = context['srsName'];
  var axisOrientation = 'enu';
  if (containerSrs) {
    var proj = ol.proj.get(containerSrs);
    if (proj) {
      axisOrientation = proj.getAxisOrientation();
    }
  }
  var coordsGroups = s.trim().split(/\s+/);
  var x, y, z;
  var flatCoordinates = [];
  for (var i = 0, ii = coordsGroups.length; i < ii; i++) {
    var coords = coordsGroups[i].split(/,+/);
    x = parseFloat(coords[0]);
    y = parseFloat(coords[1]);
    z = (coords.length === 3) ? parseFloat(coords[2]) : 0;
    if (axisOrientation.substr(0, 2) === 'en') {
      flatCoordinates.push(x, y, z);
    } else {
      flatCoordinates.push(y, x, z);
    }
  }
  return flatCoordinates;
};enu';
  if (containerSrs) {
    var proj = ol.proj.get(containerSrs);
    if (proj) {
      axisOrientation = proj.getAxisOrientation();
    }
  }
  var coordsGroups = s.trim().split(/\s+/);
  var x, y, z;
  var flatCoordinates = [];
  for (var i = 0, ii = coordsGroups.length; i < ii; i++) {
    var coords = coordsGroups[i].split(/,+/);
    x = parseFloat(coords[0]);
    y = parseFloat(coords[1]);
    z = (coords.length === 3) ? parseFloat(coords[2]) : 0;
    if (axisOrientation.substr(0, 2) === 'en') {
      flatCoordinates.push(x, y, z);
    } else {
      flatCoordinates.push(y, x, z);
    }
  }
  return flatCoordinates;
};

可以看到,在使用ol.format.GML2解析gml数据时,OL会优先使用gml数据携带的坐标系统的axis(坐标顺序)。那么再查看一下待解析的gml数据是什么样子:

<?xml version="1.0" encoding="utf-8"?>
<wfs:FeatureCollection xmlns:wfs="http://www.opengis.net/wfs" xmlns="http://www.opengis.net/wfs" xmlns:wireless="wireless.dimpt.com" xmlns:gml="http://www.opengis.net/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="wireless.dimpt.com http://10.220.97.179:8080/geoserver/wireless/wfs?service=WFS&amp;version=1.0.0&amp;request=DescribeFeatureType&amp;typeName=wireless%3Aview_rundata_cd http://www.opengis.net/wfs http://10.220.97.179:8080/geoserver/schemas/wfs/1.0.0/WFS-basic.xsd">
  <gml:boundedBy>
    <gml:null>unknown</gml:null>
  </gml:boundedBy>
  <gml:featureMember>
    <wireless:view_rundata_cd fid="view_rundata_cd.fid--75fad491_163438c7a48_-466d">
      <wireless:provinceid>JS</wireless:provinceid>
      <wireless:cityid>320100</wireless:cityid>
      <wireless:number>南京0860</wireless:number>
      <wireless:modeid>03</wireless:modeid>
      <wireless:mode>4G</wireless:mode>
      <wireless:the_geom>
        <gml:Point srsName="http://www.opengis.net/gml/srs/epsg.xml#4326">
          <gml:coordinates decimal="." cs="," ts=" ">118.53192755,31.99111585</gml:coordinates>
        </gml:Point>
      </wireless:the_geom>
    </wireless:view_rundata_cd>
  </gml:featureMember>
</wfs:FeatureCollection>

可以看到,gml数据的坐标系统的名称(code)是http://www.opengis.net/gml/srs/epsg.xml#4326。这是WGS84坐标系统的code,意味着数据的坐标系统是WGS84(这与GeoServer发布的图层坐标系统吻合)。OL中默认包含该坐标系统。并且可以看到,该feature是一个点类型,其坐标顺序是(经度,纬度)。

那么再看一下OL中有关WGS84坐标系统的定义:

ol.proj.EPSG4326.PROJECTIONS = [
  new ol.proj.EPSG4326.Projection_('CRS:84'),
  new ol.proj.EPSG4326.Projection_('EPSG:4326', 'neu'),
  new ol.proj.EPSG4326.Projection_('urn:ogc:def:crs:EPSG::4326', 'neu'),
  new ol.proj.EPSG4326.Projection_('urn:ogc:def:crs:EPSG:6.6:4326', 'neu'),
  new ol.proj.EPSG4326.Projection_('urn:ogc:def:crs:OGC:1.3:CRS84'),
  new ol.proj.EPSG4326.Projection_('urn:ogc:def:crs:OGC:2:84'),
  new ol.proj.EPSG4326.Projection_('http://www.opengis.net/gml/srs/epsg.xml#4326', 'neu'),
  new ol.proj.EPSG4326.Projection_('urn:x-ogc:def:crs:EPSG:4326', 'neu')
];

同一个坐标系统可以有许多不同的code代号,以上列出的是OL中有关WGS84的所有默认code。可以看到code为http://www.opengis.net/gml/srs/epsg.xml#4326的坐标系统带了一个参数:’neu‘。该参数指明了数据的坐标顺序为(纬度,经度,高度)。

可以看出这和gml中数据的坐标顺序不一样!

下面捋一捋:使用OL的getGetFeatureInfoUrl获得的gml数据,携带有坐标系统,code为http://www.opengis.net/gml/srs/epsg.xml#4326;另外,gml数据中坐标的顺序是(经度,纬度)。

之后使用ol.format.GML2对象读取该gml数据:OL在解析的过程中,检测到了gml数据的坐标系统,因此使用了该坐标系统,即code为http://www.opengis.net/gml/srs/epsg.xml#4326的WGS84坐标系统,其axis为’neu’(纬度,经度,高度),如此,OL把gml的坐标数据(经度,纬度)当成了(纬度,经度,高度)进行处理!这导致OL最终解析出的feature的坐标出现了经纬度颠倒的情况。

解决方法

参考github上大神的方法:

it is neu according to the EPSG database

you will need to override the axis order, code sample I’ve used before:

// override the axis orientation for WMS GetFeatureInfo
var proj = new ol.proj.Projection({
  code: 'http://www.opengis.net/gml/srs/epsg.xml#4326',
  axis: 'enu'
});
ol.proj.addEquivalentProjections([ol.proj.get('EPSG:4326'), proj]);//也可以使用ol.proj.addProjection(proj)将新的坐标系统添加进来即可,会自动覆盖原坐标系统

解决思路就是重写(override)坐标系统的axis属性。但是需要注意的是覆盖的一定得是与gml具有相同code的坐标系统,即code为http://www.opengis.net/gml/srs/epsg.xml#4326的坐标系统。

这里附上axis的可能值及其含义

axis可能值:enu,qnu,neu。

含义如下:

> The +axis switch takes three character arguments defining the axis
> orientation of the coordinate system.  The possible values are:
> 
> 'e' - easting
> 'w' - westing - an x/longitude with the opposite sign to normal.
> 'n' - northing
> 's' - southing - a y/latitude with the opposite sign to the normal.
> 'u' - up - normal z
> 'd' - down - a z/elevation with the opposite sign to the normal.

转载自:https://blog.csdn.net/a20100997/article/details/80269691

You may also like...