用OpenLayers解析GML文件

不可否认openlayers的确是个好东西,尤其是他的事件封装机制更是让人爱不释手,感谢致力于openlayers开发的脚本爱好者们。但是作为一个开源的脚本框架,它也存在不少缺陷,GML解析的低效率就是一个严重的问题。

对于一个像美国states的gml文件,大小约为300K左右,有95个面对象,所有面对象一共包含11000个左右的点,这么一个gml文件,不算从WFS请求过来的时间,就是放在本地就用openlayers脚本解析,耗时也在10s以上,虽然这里机器不太好,属于上个世纪的戴尔机器,内存256,CPU2.8G,但是这么长的耗时实在是说不过去。 

后来试用精简了的武汉数据,大小大概400K,只有一个面对象,不过这个面包含很多个点,16145左右,从WFS请求,结果在客户端根本就画不出来,IE死掉了。
后来查看openlayers解析gml数据的代码,很容易就可以发现问题。openlayers对于Geometry对象的组织是这样的,其实最基本的就是点,然后MultiPoint由点构成,继承自Openlayers.Geometry.Collection,而LinearRing,LineString均由Point构成,Polygon由OpenLayers.Geometry.LinearRing构成。
openlayers在解析数据时候,将所有的面、线包含的点全部都对象化为Openlayers.Geometry.Point,并首先将所有的对象读取到内存,得到一个Feature的集合,然后将这个集合提交给渲染器进行渲染。本来这个思想就行不通,加入我们通过WFS收到的文件有10M或者更大,要是把这些全部解析出来然后放到内存,那还不跑死啊,这个就像一个100M的文本文件要解析出来一样,要是等全部解析完了再处理数据那是不行的,万一数据再大呢,比如2G的数据,你还能这样全部读到内存么??
而其实将所有的点都对象化才是它效率低下的根本原因,本人做过测试,将16145个Openlayers.Geometry.Point在现有机器配置下实例化耗时6S(除了一个QQ外,机器不运行任何其他程序),这个解析效率显然是不能满足GIS应用的。
那么我认为,应该在gml数据解析得到相应Geometry对象的时候就直接将其用VML或SVG画出来,而且构建Polygon对象的时候不要涉及Point对象,及不要像这样构建
ring1 = new OpenLayers.Geometry.LinearRing(p.points);
rings.push(ring1);
var poly = new OpenLayers.Geometry.Polygon(rings);
最好是直接传入一系列坐标对直接构建Polygon。
笔者自己写了个解析GML的简单脚本程序,然后用VML进行绘制,绘制本地的states数据连加载到显示不要1S,绘制局域网WFS请求的武汉数据,连请求到显示不要两秒,性能有明显改善。但是笔者这个简单程序只能作为测试,数据组织方面肯定不能和openlayers相比。
附:VML和SVG是以DOM元素的形式存在与客户端用于适量数据的显示,因而二者都不能显示大数据量,它们只能作为一种辅助的形式显示少量的矢量数据。要想获得可以接受的效率,矢量对象的个数最多在1000个左右。VML和SVG的绘图效率比较低下,假如矢量对象比较多或者面对象的面积普遍较大,那么重绘也是比较慢的。
有人要看代码,所以我找出来了,找了好久,只是测试用的简单代码,没什么结构性。
<div
<div text<="" span=""><div <div=""
/*显示武汉数据1.2s*/
var hoursStart,hourEnd;//=now.getHours();
var minutesStart,minutesEnd;//=now.getMinutes();
var secondsStart,secondEnd;//=now.getSeconds();
var msStart,msEnd;
function startTime()
{
var now=new Date();
hoursStart=now.getHours();
minutesStart=now.getMinutes();
secondsStart=now.getSeconds();
msStart=now.getMilliseconds();
}
function endTime()
{
var end=new Date();
hoursEnd=end.getHours();
minutesEnd=end.getMinutes();
secondsEnd=end.getSeconds();
msEnd=end.getMilliseconds();
span.innerText+="\r\n start :"+minutesStart+":"+secondsStart+":"+msStart+"\r\nend:"+minutesEnd+":"+secondsEnd+":"+msEnd;
}

var point_count=0,poly_count=0,line_count=0,inner=0;
var inner=""; var linearRings_count=0;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//http://192.168.1.92:9090/geoserver/wfs?request=getfeature&service=wfs&version=1.0.0&typename=topp:SDE.ONEPOLYGON
var path="http://192.168.1.92:9090/GeoS_N_user/wfs?request=getfeature&service=wfs&version=1.0.0&typename=topp:SDE.WUHAN";
//武汉的数据都是小数,而vml不支持小数,所以要显示武汉数据需要把坐标放大
function load()
{
OpenLayers.loadURL("wuhan.xml", "", null, PackCall,onfail);//OpenLayers的Ajax功能我也手动做了点修改
}
function onfail(){alert("shibai");}
function PackCall(ret)
{startTime();
AnalyseXML(ret.responseText);endTime();
span.innerText=map.innerHTML;
}
function AnalyseXML(xml)//解决命名空间需要带上
{
var doc=document.createElement("root");
doc.innerHTML=xml;
var bound=doc.getElementsByTagName("boundedBy")[0].innerText;
ChangeCoordsSYS(bound,"map");
varfeatures=doc.getElementsByTagName("featureMember");
for(var i=0;i<features.length;i++)
{
var polylines=features[i].getElementsByTagName("polygonMember");
if(polylines.length>0)
{
for(var j=0;j<polylines.length;j++)
{
//poly_count+=1;
varlinearRings=polylines[j].getElementsByTagName("LinearRing");
for(var k=0;k<linearRings.length;k++)
{ linearRings_count+=1;
varcoords=linearRings[k].innerText;
var coor_arr=coords.split(' ');
AddPolygon("vectorGroup",EnlargeCoords(coords));
//inner+="\r\n"+poly_count+":"+coor_arr.length;
//point_count+=coor_arr.length;
}
}
}
}
//document.body.innerText=inner+"\r\r"+point_count;
//alert(document.getElementsByTagName("polyline").length+"--"+document.getElementsByTagName("polyline")[0].points.value);
//alert(linearRings_count);49
}
var _SCALE=2000;
function ChangeCoordsSYS(bound,mapId)
{
var twoPts=bound.split(' ');
varpt1s=twoPts[0].split(','),pt2s=twoPts[1].split(',');
document.getElementById(mapId).appendChild(document.createElement("<v:group id=\"vectorGroup\"style=\"position:absolute;left:0;top:0;z-index:1;width:100%;height:100%;z-index:2000\" />"));
vectorGroup.coordorigin.x=pt1s[0]*_SCALE;//1k
vectorGroup.coordorigin.y=pt1s[1]*_SCALE;//1k
vectorGroup.coordsize=(pt2s[0]-pt1s[0])*_SCALE+","+(pt2s[1]-pt1s[1])*_SCALE;//1k

}
function EnlargeCoords(coords)
{
var pts=coords.split(' ');
for(var i=0;i<pts.length;i++)
{
pts[i]=EnlargePt(pts[i]);
}
return pts.join(' ');
}
function EnlargePt(pt)
{
var xy=pt.split(',');
returnparseFloat(xy[0])*_SCALE+","+parseFloat(xy[1])*_SCALE;
}
function AddPolygon(group,pointsStr)
{
varnode=document.getElementById(group).appendChild(document.createElement("<v:polyline style=\"position:absolute;left:0 ;top:0 \" points=\""+pointsStr+"\" filled=\"t\" fillcolor=\"blue\" strokecolor=\"black\" strokeweight=\"1\"/>"));
node.appendChild(document.createElement("<v:fill type=\"frame\" opacity=\".4\"/>"));

//多这一步多消耗了0.3-0.4秒的时间
}

你可能感兴趣的:(JavaScript,openlayer,GML)