geoserver源码学习与扩展——kml/kmz转shapefile文件
geoserver通过工作空间Workspace-数据源DataStore-图层Layer管理地理数据,默认只支持shapefile格式的文件发布,不支持kml/kmz、csv的文件格式,所以存在将这些数据转换为shapefile的需求。
kml/kmz的文件解析基于JavaAPIforKml包完成,该包支持kml和kmz的文件解析;
import de.micromata.opengis.kml.v_2_2_0.Kml; /*解析kml文件*/ Kml kml = Kml.unmarshal(kmlFile); processKml(kml,typeName); /*解析kmz文件*/ Kml[] kmls = Kml.unmarshalFromKmz(kmzFile); for(Kml kml : kmls){ processKml(kml,typeName); }
将Kml转换为shapefile文件也是通过如下2步完成:
1、将Kml转换为FeatureCollection;
2、利用ShapefileDumper类将FeatureCollection转存到硬盘(详见http://www.cnblogs.com/HandyLi/p/8616115.html,不再赘述);
1 /* 2 * Kml to FeatureCollection 3 */ 4 private void processKml(Kml kml, String typeName){ 5 try{ 6 Feature kmlFeature = kml.getFeature(); 7 if(kmlFeature instanceof Document){ 8 Document doc = (Document)kmlFeature; 9 10 List<Feature> folderList = doc.getFeature(); 11 for(Feature folder: folderList){ 12 if(folder instanceof Folder){ 13 //one Folder to one SimpleFeatureCollection 14 //get Field info 15 List<String> typeSpec = new ArrayList<String>(); 16 typeSpec.add("the_geom:Point:srid="+ SRID);// <- the geometry attribute: Point type 17 typeSpec.add("name:String"); 18 List<SimpleField> simpleFields = doc.getSchema().get(0).getSimpleField(); 19 for(SimpleField simField : simpleFields){ 20 String fieldType = simField.getType(); 21 String fieldName = simField.getName(); 22 typeSpec.add(fieldName + ":" + fieldType); 23 } 24 if(CreateCluster)//add Field:cluster 25 typeSpec.add("cluster:String"); 26 String typeSpecs = String.join(",", typeSpec); 27 final SimpleFeatureType TYPE = DataUtilities.createType(typeName, 28 typeSpecs // all attributes 29 ); 30 31 SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE); 32 /* 33 * We create a FeatureCollection into which we will put each Feature created from a record 34 * in the input csv data file 35 */ 36 ListFeatureCollection collection = new ListFeatureCollection(TYPE); 37 38 List<Feature> placeList = ((Folder) folder).getFeature(); 39 for(Feature place: placeList){ 40 if(place instanceof Placemark){ 41 Geometry kmlGeo = ((Placemark)place).getGeometry(); 42 com.vividsolutions.jts.geom.Geometry jtsGeom = toJTSGeometry(kmlGeo); 43 featureBuilder.add(jtsGeom); 44 //Placemark name value 45 featureBuilder.add(((Placemark)place).getName()); 46 47 ExtendedData exData = ((Placemark)place).getExtendedData(); 48 List<SimpleData> simDatas = exData.getSchemaData().get(0).getSimpleData(); 49 for(SimpleData sData : simDatas){ 50 featureBuilder.add(sData.getValue()); 51 } 52 if(CreateCluster) 53 featureBuilder.add(""); //add cluster field value 54 SimpleFeature feature = featureBuilder.buildFeature(null); 55 collection.add(feature); 56 } 57 } 58 // write to shapefile 59 writeShapeFile(collection); 60 } 61 } 62 } 63 } 64 catch(Exception ex){ 65 throw new IllegalArgumentException("KML parse error: " + ex.getMessage()); 66 } 67 }
注意:toJTSGeometry函数用于将Kml封装的Geometry类转换为JTS库里的Geometry类。
1 /* 2 * de.micromata.opengis.kml.v_2_2_0.Geometry transform to com.vividsolutions.jts.geom.Geometry 3 */ 4 private com.vividsolutions.jts.geom.Geometry toJTSGeometry(Geometry kmlGeo){ 5 if(kmlGeo == null) 6 return null; 7 8 GeometryFactory geoFactory = JTSFactoryFinder.getGeometryFactory(null); 9 if(kmlGeo instanceof MultiGeometry){ 10 List<com.vividsolutions.jts.geom.Geometry> geoList = new ArrayList<com.vividsolutions.jts.geom.Geometry>(); 11 List<Geometry> kmlGeoList = ((MultiGeometry)kmlGeo).getGeometry(); 12 for(Geometry kmlSubGeo : kmlGeoList){ 13 geoList.add(toJTSGeometry(kmlSubGeo)); 14 } 15 GeometryCollection gc = geoFactory.createGeometryCollection(geoList.toArray(new com.vividsolutions.jts.geom.Geometry[0])); 16 return gc; 17 } 18 else if(kmlGeo instanceof de.micromata.opengis.kml.v_2_2_0.Point){ 19 double dLong = ((de.micromata.opengis.kml.v_2_2_0.Point)kmlGeo).getCoordinates().get(0).getLongitude(); 20 double dLat = ((de.micromata.opengis.kml.v_2_2_0.Point)kmlGeo).getCoordinates().get(0).getLatitude(); 21 return geoFactory.createPoint(new Coordinate(dLong, dLat)); 22 } 23 else if(kmlGeo instanceof LineString){ 24 List<Coordinate> geoCoords = new ArrayList<Coordinate>(); 25 26 List<de.micromata.opengis.kml.v_2_2_0.Coordinate> coordList = ((LineString)kmlGeo).getCoordinates(); 27 for(de.micromata.opengis.kml.v_2_2_0.Coordinate kmlCoord : coordList){ 28 double dLong = kmlCoord.getLongitude(); 29 double dLat = kmlCoord.getLatitude(); 30 geoCoords.add(new Coordinate(dLong, dLat)); 31 } 32 return geoFactory.createLineString(geoCoords.toArray(new Coordinate[0])); 33 } 34 else if(kmlGeo instanceof LinearRing){ 35 List<Coordinate> geoCoords = new ArrayList<Coordinate>(); 36 List<de.micromata.opengis.kml.v_2_2_0.Coordinate> coordList = ((LinearRing)kmlGeo).getCoordinates(); 37 for(de.micromata.opengis.kml.v_2_2_0.Coordinate kmlCoord : coordList){ 38 double dLong = kmlCoord.getLongitude(); 39 double dLat = kmlCoord.getLatitude(); 40 geoCoords.add(new Coordinate(dLong, dLat)); 41 } 42 return geoFactory.createLinearRing(geoCoords.toArray(new Coordinate[0])); 43 } 44 else if(kmlGeo instanceof Polygon){ 45 List<com.vividsolutions.jts.geom.LinearRing> holes = new ArrayList<com.vividsolutions.jts.geom.LinearRing>(); 46 com.vividsolutions.jts.geom.LinearRing shell = convertLinearRing(geoFactory, ((Polygon)kmlGeo).getOuterBoundaryIs().getLinearRing()); 47 List<Boundary> innerBoundaryList = ((Polygon)kmlGeo).getInnerBoundaryIs(); 48 for(Boundary inner : innerBoundaryList){ 49 holes.add(convertLinearRing(geoFactory,inner.getLinearRing())); 50 } 51 return geoFactory.createPolygon(shell, holes.toArray(new com.vividsolutions.jts.geom.LinearRing[0])); 52 } 53 else{ 54 throw new IllegalArgumentException("Unrecognized geometry type: " + kmlGeo); 55 } 56 } 57 private com.vividsolutions.jts.geom.LinearRing convertLinearRing(GeometryFactory geoFactory, LinearRing geometry){ 58 List<Coordinate> geoCoords = new ArrayList<Coordinate>(); 59 List<de.micromata.opengis.kml.v_2_2_0.Coordinate> coordList = (geometry).getCoordinates(); 60 for(de.micromata.opengis.kml.v_2_2_0.Coordinate kmlCoord : coordList){ 61 double dLong = kmlCoord.getLongitude(); 62 double dLat = kmlCoord.getLatitude(); 63 geoCoords.add(new Coordinate(dLong, dLat)); 64 } 65 return geoFactory.createLinearRing(geoCoords.toArray(new Coordinate[0])); 66 67 }