diff --git a/.gitignore b/.gitignore index b6a9129..b2eec8a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,4 @@ examples/mars/ src/main/docs/output/ src/main/docs/images/ src/main/docs/commands/ - +TODO.md diff --git a/src/main/docs/layer.adoc b/src/main/docs/layer.adoc index 41ec6ec..6ed15a8 100644 --- a/src/main/docs/layer.adoc +++ b/src/main/docs/layer.adoc @@ -338,6 +338,46 @@ include::output/layer_remove_5_result.txt[] include::output/layer_remove_6_command.txt[] include::output/layer_remove_6_result.txt[] +==== Write + +include::commands/layer_write_description.txt[] + +include::output/layer_write_4_command.txt[] + +include::commands/layer_write.txt[] + +include::output/layer_write_0_command.txt[] +include::output/layer_write_0_result.txt[] + +include::output/layer_write_1_command.txt[] +include::output/layer_write_1_result.txt[] + +include::output/layer_write_2_command.txt[] +include::output/layer_write_2_result.txt[] + +include::output/layer_write_3_command.txt[] +include::output/layer_write_3_result.txt[] + +include::output/layer_write_4_command.txt[] +include::output/layer_write_4_result.txt[] + +==== Read + +include::commands/layer_read_description.txt[] + +include::output/layer_read_1_command.txt[] + +include::commands/layer_read.txt[] + +include::output/layer_read_0_command.txt[] +include::output/layer_read_0_result.txt[] + +include::output/layer_read_1_command.txt[] +include::output/layer_read_1_result.txt[] + +include::output/layer_read_2_command.txt[] +include::output/layer_read_2_result.txt[] + ==== Update Field include::commands/layer_updatefield_description.txt[] diff --git a/src/main/groovy/org/geoshell/vector/LayerCommands.groovy b/src/main/groovy/org/geoshell/vector/LayerCommands.groovy index 08500a0..6587ccf 100644 --- a/src/main/groovy/org/geoshell/vector/LayerCommands.groovy +++ b/src/main/groovy/org/geoshell/vector/LayerCommands.groovy @@ -13,12 +13,25 @@ import geoscript.geom.Point import geoscript.layer.Graticule import geoscript.layer.Layer import geoscript.layer.Writer as LayerWriter +import geoscript.layer.io.CsvReader +import geoscript.layer.io.GeoJSONReader +import geoscript.layer.io.GeoRSSWriter +import geoscript.layer.io.GeobufWriter +import geoscript.layer.io.GmlWriter +import geoscript.layer.io.GpxWriter +import geoscript.layer.io.KmlWriter +import geoscript.layer.io.MvtWriter +import geoscript.layer.io.Reader +import geoscript.layer.io.Writer +import geoscript.layer.io.Writers +import geoscript.layer.io.YamlReader import geoscript.proj.Projection import geoscript.style.Style import geoscript.style.io.CSSReader import geoscript.style.io.SLDReader import geoscript.style.io.SLDWriter import geoscript.workspace.Workspace +import org.apache.commons.io.FilenameUtils import org.geoshell.Catalog import org.springframework.beans.factory.annotation.Autowired import org.springframework.shell.core.CommandMarker @@ -1693,4 +1706,71 @@ class LayerCommands implements CommandMarker { } } + @CliCommand(value = "layer write", help = "Write a Layer to GeoJSON, CSV, or KML.") + String write( + @CliOption(key = "name", mandatory = true, help = "The Layer name") LayerName name, + @CliOption(key = "format", mandatory = true, help = "The format") String format, + @CliOption(key = "file", mandatory = false, help = "The output file") File file + ) throws Exception { + Layer layer = catalog.layers[name] + if (layer) { + Writer writer = Writers.find(format) + if (file) { + writer.write(layer, file) + "Layer ${name} written to ${file} as ${format}" + } else { + writer.write(layer) + } + } else { + "Unable to find Layer ${name}" + } + } + + @CliCommand(value = "layer read", help = "Read a Layer from a GeoJSON, KML, or YAML file.") + String read( + @CliOption(key = "workspace", mandatory = true, help = "The Workspace name") WorkspaceName workspaceName, + @CliOption(key = "name", mandatory = true, help = "The name") String name, + @CliOption(key = "file", mandatory = true, help = "The output file") File file + ) throws Exception { + Workspace workspace = catalog.workspaces[workspaceName] + if (workspace) { + String fileExtension = FilenameUtils.getExtension(file.name) + Reader reader = getReaderForFileExtension(fileExtension) + if (reader) { + Layer layer = reader.read(file) + workspace.add(layer) + catalog.layers[new LayerName(name)] = layer + "Created Layer ${name} in Workspace ${workspaceName} for ${file}!" + } else { + "Unable to find reader for ${file}!" + } + } else { + "Unable to find Workspace ${workspaceName}" + } + } + + private Reader getReaderForFileExtension(String fileExtension) { + Reader reader + if (fileExtension.equalsIgnoreCase("csv")) { + reader = new CsvReader() + } else if (fileExtension.equalsIgnoreCase("json")) { + reader = new GeoJSONReader() + } else if (fileExtension.equalsIgnoreCase("yml") || fileExtension.equalsIgnoreCase("yaml")) { + reader = new YamlReader() + } else if (fileExtension.equalsIgnoreCase("geobuf") || fileExtension.equalsIgnoreCase("pbf")) { + reader = new GeobufWriter() + } else if (fileExtension.equalsIgnoreCase("mvt")) { + reader = new MvtWriter() + } else if (fileExtension.equalsIgnoreCase("gml")) { + reader = new GmlWriter() + } else if (fileExtension.equalsIgnoreCase("kml")) { + reader = new KmlWriter() + } else if (fileExtension.equalsIgnoreCase("rss")) { + reader = new GeoRSSWriter() + } else if (fileExtension.equalsIgnoreCase("gpx")) { + reader = new GpxWriter() + } + reader + } + } diff --git a/src/test/groovy/org/geoshell/docs/LayerDocTest.groovy b/src/test/groovy/org/geoshell/docs/LayerDocTest.groovy index 3c32a6f..5349fcb 100644 --- a/src/test/groovy/org/geoshell/docs/LayerDocTest.groovy +++ b/src/test/groovy/org/geoshell/docs/LayerDocTest.groovy @@ -238,6 +238,26 @@ class LayerDocTest extends AbstractDocTest { ]) } + @Test + void write() { + run("layer_write", [ + 'workspace open --name mem --params memory', + 'layer create --workspace mem --name points --fields "the_geom=Point EPSG:4326|fid=Int|name=String"', + 'layer add --name points --values "the_geom=POINT (-122.333056 47.609722)|fid=1|name=Seattle"', + 'layer add --name points --values "the_geom=POINT (-122.459444 47.241389)|fid=2|name=Tacoma"', + 'layer write --name points --format geojson --file src/main/docs/output/points.json' + ]) + } + + @Test + void read() { + run("layer_read", [ + 'workspace open --name mem --params memory', + 'layer read --workspace mem --name points --file src/test/resources/points.json', + 'layer features --name points' + ]) + } + @Test void updateField() { run("layer_updatefield", [ diff --git a/src/test/groovy/org/geoshell/vector/LayerCommandsTest.groovy b/src/test/groovy/org/geoshell/vector/LayerCommandsTest.groovy index 6b08bf2..de527c2 100644 --- a/src/test/groovy/org/geoshell/vector/LayerCommandsTest.groovy +++ b/src/test/groovy/org/geoshell/vector/LayerCommandsTest.groovy @@ -1235,4 +1235,35 @@ class LayerCommandsTest { Layer layer = catalog.layers[new LayerName("hexagons")] assertEquals 219, layer.count } + + @Test void write() { + Catalog catalog = new Catalog() + catalog.workspaces[new WorkspaceName("mem")] = new Memory() + LayerCommands cmds = new LayerCommands(catalog: catalog) + + cmds.create(new WorkspaceName("mem"), "points", "geom=Point EPSG:4326|id=Int|name=String") + cmds.add(new LayerName("points"), "geom=POINT(1 1)|id=1|name=Home") + cmds.add(new LayerName("points"), "geom=POINT(2 2)|id=2|name=Work") + + File file = new File(folder, "points.json") + String results = cmds.write(new LayerName("points"), "geojson", file) + assertTrue(results.startsWith("Layer points written to")) + assertTrue(results.endsWith("points.json as geojson")) + assertTrue(file.text.startsWith("""{"type":"FeatureCollection""")) + println file.text + } + + @Test void read() { + Catalog catalog = new Catalog() + catalog.workspaces[new WorkspaceName("mem")] = new Memory() + LayerCommands cmds = new LayerCommands(catalog: catalog) + + File file = new File(getClass().getClassLoader().getResource("points.json").toURI()) + String result = cmds.read(new WorkspaceName("mem"), "points", file) + assertTrue(result.startsWith("Created Layer points in Workspace mem for")) + assertTrue(result.endsWith("points.json!")) + + Layer layer = catalog.layers[new LayerName("points")] + assertEquals(2, layer.count) + } } diff --git a/src/test/resources/points.json b/src/test/resources/points.json new file mode 100644 index 0000000..7a935a2 --- /dev/null +++ b/src/test/resources/points.json @@ -0,0 +1,35 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 1, + 1 + ] + }, + "properties": { + "id": 1, + "name": "Home" + }, + "id": "1" + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 2, + 2 + ] + }, + "properties": { + "id": 2, + "name": "Work" + }, + "id": "2" + } + ] +} \ No newline at end of file