Skip to content

Commit 64c489f

Browse files
committed
Improve csv reading when a semi-colon is part of the name and not a separator for the type
1 parent b65ac7f commit 64c489f

4 files changed

Lines changed: 57 additions & 5 deletions

File tree

src/main/groovy/geoscript/feature/Schema.groovy

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ class Schema {
469469
* @param alias The alias
470470
* @return The GeoTools binding class name
471471
*/
472-
static lookUpBinding(String alias) {
472+
static String lookUpBinding(String alias) {
473473
Map map = [
474474
("geoscript.geom.LinearRing".toLowerCase()) : "org.locationtech.jts.geom.LinearRing",
475475
("LinearRing".toLowerCase()) : "org.locationtech.jts.geom.LinearRing",
@@ -508,6 +508,16 @@ class Schema {
508508
map.get(alias.toLowerCase(), alias)
509509
}
510510

511+
static boolean isValidFieldType(String type) {
512+
boolean isValid = true
513+
try {
514+
Class.forName(Schema.lookUpBinding(type))
515+
} catch(ClassNotFoundException ex) {
516+
isValid = false
517+
}
518+
isValid
519+
}
520+
511521
/**
512522
* Build a SimpleFeatureType from the name and a List of Fields.
513523
* @param name The name

src/main/groovy/geoscript/layer/io/CsvReader.groovy

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,14 @@ class CsvReader implements Reader {
218218
name = parts[0]
219219
type = parts[1]
220220
}
221-
new Field(name, type)
221+
// Make sure the type is valid
222+
if (Schema.isValidFieldType(type)) {
223+
new Field(name, type)
224+
}
225+
// Otherwise fall back
226+
else {
227+
new Field("${name}:${type}", "String")
228+
}
222229
}
223230
fields.add(new Field("geom", "Point"))
224231
Schema schema = new Schema(layerName, fields)
@@ -245,8 +252,8 @@ class CsvReader implements Reader {
245252
def v = values[i]
246253
def colType = "String"
247254
def proj = null
248-
// Get the type from the header
249-
if (c.contains(":")) {
255+
// Get the type from the header (if the type is valid)
256+
if (c.contains(":") && Schema.isValidFieldType(c.split(":")[1])) {
250257
String[] parts = c.split(":")
251258
c = parts[0]
252259
colType = parts[1]
@@ -293,6 +300,9 @@ class CsvReader implements Reader {
293300
Map valueMap = [:]
294301
cols.eachWithIndex {c,i ->
295302
String colName = getColumnName(c)
303+
if (!layer.schema.has(colName)) {
304+
colName = c
305+
}
296306
def v = values[i]
297307
if (usingSingleColumn && colName.equalsIgnoreCase(column)) {
298308
if (isGeom) {
@@ -400,7 +410,11 @@ class CsvReader implements Reader {
400410
str.startsWith("MULTILINESTRING (") || str.startsWith("MULTILINESTRING(") ||
401411
str.startsWith("MULTIPOLYGON") || str.startsWith("MULTIPOLYGON(") ||
402412
str.startsWith("GEOMETRYCOLLECTION (") || str.startsWith("GEOMETRYCOLLECTION(") ||
403-
str.startsWith("LINEARRING (") || str.startsWith("LINEARRING(")
413+
str.startsWith("LINEARRING (") || str.startsWith("LINEARRING(") ||
414+
str.startsWith("CIRCULARSTRING (") || str.startsWith("CIRCULARSTRING(") ||
415+
str.startsWith("CIRCULARRING (") || str.startsWith("CIRCULARRING(") ||
416+
str.startsWith("COMPOUNDCURVE (") || str.startsWith("COMPOUNDCURVE(") ||
417+
str.startsWith("COMPOUNDRING (") || str.startsWith("COMPOUNDRING(")
404418
) {
405419
return true
406420
}

src/test/groovy/geoscript/feature/SchemaTestCase.groovy

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,20 @@ class SchemaTestCase {
319319
assertEquals "org.geotools.geometry.jts.CompoundCurve", Schema.lookUpBinding("CompoundCurve")
320320
}
321321

322+
@Test void isValidFieldType() {
323+
assertTrue(Schema.isValidFieldType("str"))
324+
assertTrue(Schema.isValidFieldType("string"))
325+
assertTrue(Schema.isValidFieldType("java.lang.String"))
326+
assertTrue(Schema.isValidFieldType("Point"))
327+
assertTrue(Schema.isValidFieldType("geoscript.geom.Point"))
328+
assertTrue(Schema.isValidFieldType("int"))
329+
assertTrue(Schema.isValidFieldType("integer"))
330+
331+
assertFalse(Schema.isValidFieldType("asdf"))
332+
assertFalse(Schema.isValidFieldType("junk"))
333+
assertFalse(Schema.isValidFieldType("inter"))
334+
}
335+
322336
@Test void spec() {
323337
Schema s1 = new Schema("widgets", [new Field("geom","Point"), new Field("name","string"), new Field("price","float")])
324338
assertEquals "geom:Point,name:String,price:Float", s1.spec

src/test/groovy/geoscript/layer/io/CsvReaderTestCase.groovy

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,20 @@ class CsvReaderTestCase {
3939
}
4040
}
4141

42+
@Test void readWKTWithSemiColons() {
43+
String csv = """"geom:geom","name:x","price:y"
44+
"POINT (111 -47)","House","12.5"
45+
"POINT (121 -45)","School","22.7"
46+
"""
47+
CsvReader reader = new CsvReader()
48+
Layer layer = reader.read(csv)
49+
assertEquals("csv geom:geom: Point, name:x: String, price:y: String", layer.schema.toString())
50+
assertEquals(2, layer.count)
51+
layer.eachFeature { f ->
52+
assertTrue(f.geom instanceof geoscript.geom.Point)
53+
}
54+
}
55+
4256
@Test void readWKTWithTypesAndProj() {
4357
String csv = """"geom:Point:EPSG:4326","name:String","price:Double"
4458
"POINT (111 -47)","House","12.5"

0 commit comments

Comments
 (0)