1

I'm trying to use the CSV2SHP tutorial. I spent some time trying to get it to run but using v10.x of Geotools causes the shapefile to be output with no geometries. For instance if I open it in QGIS, the layer is present and the attributes can be viewed in the table but there are no points on the map. QGIS reports the extent as xMin,yMin -1,-1 : xMax,yMax 0,0.

I've just tried using version 9.0 and it works as expected. Can anyone explain what changed between 9 and 10 to cause this to break? It's quite puzzling as the tutorial seems to have been written for v10.

I've pasted the full code from the tutorial (including some minor edits) below.

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import org.geotools.data.DefaultTransaction;
import org.geotools.data.Transaction;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.data.simple.SimpleFeatureStore;
import org.geotools.feature.DefaultFeatureCollection;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.swing.data.JFileDataStoreChooser;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;

/**
 * This example reads data for point locations and associated attributes from a comma separated text
* (CSV) file and exports them as a new shapefile. It illustrates how to build a feature type.
 * <p>
 * Note: to keep things simple in the code below the input file should not have additional spaces or
 * tabs between fields.
 */
public class Csv2Shape {

    public static void main(String[] args) throws Exception {

        File file = JFileDataStoreChooser.showOpenFile("csv", null);
        if (file == null) {
            return;
        }

        /*
         * We use the DataUtilities class to create a FeatureType that will describe the data in our
         * shapefile.
         * 
         * See also the createFeatureType method below for another, more flexible approach.
         */
        final SimpleFeatureType TYPE = createFeatureType();


    /*
     * We create a FeatureCollection into which we will put each Feature created from a record
     * in the input csv data file
     */
    DefaultFeatureCollection collection = new DefaultFeatureCollection();

    /*
     * GeometryFactory will be used to create the geometry attribute of each feature (a Point
     * object for the location)
     */
    GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);

    SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);

    BufferedReader reader = new BufferedReader(new FileReader(file));
    try {
        /* First line of the data file is the header */
        String line = reader.readLine();
        System.out.println("Header: " + line);

        for (line = reader.readLine(); line != null; line = reader.readLine()) {
            if (line.trim().length() > 0) { // skip blank lines
                String tokens[] = line.split("\\,");

                double latitude = Double.parseDouble(tokens[0]);
                double longitude = Double.parseDouble(tokens[1]);

                System.out.println("lat : "+latitude);
                System.out.println("lon : "+longitude);

                String name = tokens[2].trim();
                int number = Integer.parseInt(tokens[3].trim());

                /* Longitude (= x coord) first ! */
                Point point = geometryFactory.createPoint(new Coordinate(longitude, latitude));

                featureBuilder.add(point);
                featureBuilder.add(name);
                SimpleFeature feature = featureBuilder.buildFeature(null);
                collection.add(feature);
            }
        }
    } finally {
        reader.close();
    }

    /*
     * Get an output file name and create the new shapefile
     */
    File newFile = getNewShapeFile(file);

    ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();

    Map<String, Serializable> params = new HashMap<String, Serializable>();
    params.put("url", newFile.toURI().toURL());
    params.put("create spatial index", Boolean.TRUE);

    ShapefileDataStore newDataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
    newDataStore.createSchema(TYPE);

    /*
     * You can comment out this line if you are using the createFeatureType method (at end of
     * class file) rather than DataUtilities.createType
     */
    newDataStore.forceSchemaCRS(DefaultGeographicCRS.WGS84);

    /*
     * Write the features to the shapefile
     */
    Transaction transaction = new DefaultTransaction("create");

    String typeName = newDataStore.getTypeNames()[0];
    SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName);

    if (featureSource instanceof SimpleFeatureStore) {
        SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;

        featureStore.setTransaction(transaction);
        try {
            featureStore.addFeatures(collection);
            transaction.commit();

        } catch (Exception problem) {
            problem.printStackTrace();
            transaction.rollback();

        } finally {
            transaction.close();
        }
        System.exit(0); // success!
    } else {
        System.out.println(typeName + " does not support read/write access");
        System.exit(1);
    }
}

/**
 * Prompt the user for the name and path to use for the output shapefile
 * 
 * @param csvFile
 *            the input csv file used to create a default shapefile name
 * 
 * @return name and path for the shapefile as a new File object
 */
private static File getNewShapeFile(File csvFile) {
    String path = csvFile.getAbsolutePath();
    String newPath = path.substring(0, path.length() - 4) + ".shp";

    JFileDataStoreChooser chooser = new JFileDataStoreChooser("shp");
    chooser.setDialogTitle("Save shapefile");
    chooser.setSelectedFile(new File(newPath));

    int returnVal = chooser.showSaveDialog(null);

    if (returnVal != JFileDataStoreChooser.APPROVE_OPTION) {
        // the user cancelled the dialog
        System.exit(0);
    }

    File newFile = chooser.getSelectedFile();
    if (newFile.equals(csvFile)) {
        System.out.println("Error: cannot replace " + csvFile);
        System.exit(0);
    }

    return newFile;
}

/**
 * Here is how you can use a SimpleFeatureType builder to create the schema for your shapefile
 * dynamically.
 * <p>
 * This method is an improvement on the code used in the main method above (where we used
 * DataUtilities.createFeatureType) because we can set a Coordinate Reference System for the
 * FeatureType and a a maximum field length for the 'name' field dddd
 */
private static SimpleFeatureType createFeatureType() {

    SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
    builder.setName("Location");
    builder.setCRS(DefaultGeographicCRS.WGS84); // <- Coordinate reference system

        // add attributes in order
        builder.add("Location", Point.class);
        builder.length(15).add("Name", String.class); // <- 15 chars width for name field

    // build the type
    final SimpleFeatureType LOCATION = builder.buildFeatureType();

    return LOCATION;
   }

}
  • Welcome to gis.SE. Can you tell us exactly which version(s) you tried? Also, are you using a mvn repository version or local build? – BradHards Dec 20 '13 at 3:25
  • I'm using the geotools maven repository. Both v10.3 and 10.0 fail, but v9.0 works. I haven't tried any others but can do if that helps. – PeteBrew Dec 20 '13 at 3:55
  • Can you add your "edit" as an answer? Then mark it as "the answer", so this gets closed off (you may need to wait a day or two). – BradHards Dec 20 '13 at 9:32
  • try calling your geometry "the_geom" instead of "location" - the new Shapefile writer cares about the name while the old one ignored the spec. – Ian Turton Dec 20 '13 at 10:56
  • @BradHards - I'm a lowly newbie so I'm not allowed to answer my own question. Feel free to cut n paste it as a response and I'll mark it as accepted. – PeteBrew Dec 20 '13 at 15:05
0

The asker figured it out. There are two very similar pages, one written for 9.x and then modified for 10.x and re-posted. He'd found both through Google and had them open alongside a lot of other tabs in his web browser. For the record they are:

He said:

So you can understand my mistake! It's a little frustrating that there is no indication on the older version but I'll let the authors off as it's a very nice tutorial in every other respect. If someone with access to these pages reads this - please add a note to stop others wasting several hours like me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.