diff --git a/io/plugins/eu.esdihumboldt.hale.io.csv/META-INF/MANIFEST.MF b/io/plugins/eu.esdihumboldt.hale.io.csv/META-INF/MANIFEST.MF index 960bb14853..38424958d4 100644 --- a/io/plugins/eu.esdihumboldt.hale.io.csv/META-INF/MANIFEST.MF +++ b/io/plugins/eu.esdihumboldt.hale.io.csv/META-INF/MANIFEST.MF @@ -30,6 +30,7 @@ Import-Package: au.com.bytecode.opencsv;version="2.3.0", eu.esdihumboldt.hale.common.lookup, eu.esdihumboldt.hale.common.lookup.impl, eu.esdihumboldt.hale.common.schema, + eu.esdihumboldt.hale.common.schema.geometry, eu.esdihumboldt.hale.common.schema.io, eu.esdihumboldt.hale.common.schema.io.impl, eu.esdihumboldt.hale.common.schema.model, diff --git a/io/plugins/eu.esdihumboldt.hale.io.csv/src/eu/esdihumboldt/hale/io/csv/writer/AbstractTableInstanceWriter.java b/io/plugins/eu.esdihumboldt.hale.io.csv/src/eu/esdihumboldt/hale/io/csv/writer/AbstractTableInstanceWriter.java index 2e1bc318e6..f89b504497 100644 --- a/io/plugins/eu.esdihumboldt.hale.io.csv/src/eu/esdihumboldt/hale/io/csv/writer/AbstractTableInstanceWriter.java +++ b/io/plugins/eu.esdihumboldt.hale.io.csv/src/eu/esdihumboldt/hale/io/csv/writer/AbstractTableInstanceWriter.java @@ -22,7 +22,13 @@ import javax.xml.namespace.QName; -import eu.esdihumboldt.hale.common.instance.io.impl.AbstractInstanceWriter; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.GeometryCollection; + +import eu.esdihumboldt.hale.common.core.io.report.IOReporter; +import eu.esdihumboldt.hale.common.instance.geometry.DefaultGeometryProperty; +import eu.esdihumboldt.hale.common.instance.io.impl.AbstractGeoInstanceWriter; +import eu.esdihumboldt.hale.common.instance.io.util.EnumWindingOrderTypes; import eu.esdihumboldt.hale.common.instance.model.Group; import eu.esdihumboldt.hale.common.instance.model.Instance; import eu.esdihumboldt.hale.common.instance.model.InstanceCollection; @@ -36,7 +42,7 @@ * * @author Patrick Lieb */ -public abstract class AbstractTableInstanceWriter extends AbstractInstanceWriter { +public abstract class AbstractTableInstanceWriter extends AbstractGeoInstanceWriter { /** * @see eu.esdihumboldt.hale.common.core.io.IOProvider#isCancelable() @@ -57,11 +63,12 @@ public boolean isCancelable() { * @param useSchema true if properties should be defined from * the schema, otherwise false and properties are * defined from the Instances + * @param reporter IOReporter * @return a map of properties with string of localpart of the QName of the * property as key */ protected Map getPropertyMap(Instance instance, List headerRow, - boolean useSchema, boolean solveNestedProperties) { + boolean useSchema, boolean solveNestedProperties, IOReporter reporter) { // properties of current instance Iterable allProperties; if (!useSchema) { @@ -88,16 +95,16 @@ protected Map getPropertyMap(Instance instance, List hea // if property is an OInstance or OGroup, it's a nested property if (solveNestedProperties && property instanceof Group) { Group nextInstance = (Group) property; - iterateBuild(nextInstance, qname, headerRow, row, cellValue); + iterateBuild(nextInstance, qname, headerRow, row, cellValue, reporter); } else { // add property with corresponding cellValue (localpart) to // map if (property instanceof Group && shouldBeDisplayed(property)) { - checkValue((Group) property, headerRow, row, cellValue); + checkValue((Group) property, headerRow, row, cellValue, reporter); } else { - addProperty(headerRow, row, property, cellValue); + addProperty(headerRow, row, property, cellValue, reporter); } } @@ -115,17 +122,17 @@ else if (useSchema) { // property if (solveNestedProperties && property instanceof Group) { Group nextInstance = (Group) property; - iterateBuild(nextInstance, qname, headerRow, row, cellValue); + iterateBuild(nextInstance, qname, headerRow, row, cellValue, reporter); } else { // add property with corresponding cellValue (localpart) // to // map if (property instanceof Group && shouldBeDisplayed(property)) { - checkValue((Group) property, headerRow, row, cellValue); + checkValue((Group) property, headerRow, row, cellValue, reporter); } else { - addProperty(headerRow, row, property, cellValue); + addProperty(headerRow, row, property, cellValue, reporter); } } } @@ -135,7 +142,7 @@ else if (useSchema) { if (shouldBeDisplayed(property)) { cellValue = qname.getLocalPart(); } - addProperty(headerRow, row, property, cellValue); + addProperty(headerRow, row, property, cellValue, reporter); } // close else } // close else-if @@ -155,8 +162,8 @@ else if (useSchema) { * @return a map of properties with string of localpart of the QName of the * property as key */ - protected Map getPropertyMap(TypeDefinition definition, - List headerRow) { + protected Map getPropertyMap(TypeDefinition definition, List headerRow, + IOReporter reporter) { Iterable allProperties = DefinitionUtil.getAllProperties(definition).stream() .map(def -> def.getName()).collect(Collectors.toList()); Map row = new HashMap(); @@ -167,7 +174,7 @@ protected Map getPropertyMap(TypeDefinition definition, if (shouldBeDisplayed(property)) { cellValue = qname.getLocalPart(); } - addProperty(headerRow, row, property, cellValue); + addProperty(headerRow, row, property, cellValue, reporter); } @@ -184,11 +191,11 @@ protected Map getPropertyMap(TypeDefinition definition, * instance name/path */ private void iterateBuild(Group instance, QName qNameOfTheInstance, List headerRow, - Map row, String propertyPath) { + Map row, String propertyPath, IOReporter reporter) { if (shouldBeDisplayed(instance)) { // check if the actual instance has a value an add it - checkValue(instance, headerRow, row, propertyPath); + checkValue(instance, headerRow, row, propertyPath, reporter); } // children properties of current instance Iterable children = instance.getPropertyNames(); @@ -198,17 +205,19 @@ private void iterateBuild(Group instance, QName qNameOfTheInstance, List // only the first instance Object child = instance.getProperty(qname)[0]; if (child instanceof Group && shouldBeDisplayed(child)) { + iterateBuild((Group) instance.getProperty(qname)[0], qname, headerRow, row, - propertyPath + "." + qname.getLocalPart()); + propertyPath + "." + qname.getLocalPart(), reporter); } else if (child instanceof Group) { // the child is a choice or packege, etc. iterateBuild((Group) instance.getProperty(qname)[0], qname, headerRow, row, - propertyPath); + propertyPath, reporter); } else { // child is an attribute - addProperty(headerRow, row, child, propertyPath + "." + qname.getLocalPart()); + addProperty(headerRow, row, child, propertyPath + "." + qname.getLocalPart(), + reporter); } } @@ -225,20 +234,40 @@ private boolean shouldBeDisplayed(Object obj) { } private void addProperty(List headerRow, Map row, Object property, - String propertyTypeName) { + String propertyTypeName, IOReporter reporter) { if (!headerRow.contains(propertyTypeName)) { headerRow.add(propertyTypeName); } + + if (property instanceof DefaultGeometryProperty) { + // Property is an instance of DefaultGeometryProperty + DefaultGeometryProperty geometryProperty = (DefaultGeometryProperty) property; + + Geometry geometry = geometryProperty.getGeometry(); + + // correct winding order as per right-hand rule, i.e., + // exterior rings are counterclockwise, and holes are + // clockwise. + setWindingOrder(EnumWindingOrderTypes.counterClockwise); + property = unifyGeometry(geometry, reporter, + geometryProperty.getCRSDefinition().getCRS()); + + if (geometry instanceof GeometryCollection + && ((GeometryCollection) geometry).getNumGeometries() == 1) { + property = geometryProperty.getGeometry().getGeometryN(0); + } + } + row.put(propertyTypeName, property); } // check if value of current property isn't null and add it private void checkValue(Group group, List headerRow, Map row, - String propertyTypeName) { + String propertyTypeName, IOReporter reporter) { if (group instanceof Instance) { Object value = ((Instance) group).getValue(); if (value != null) { - addProperty(headerRow, row, value, propertyTypeName); + addProperty(headerRow, row, value, propertyTypeName, reporter); } } } diff --git a/io/plugins/eu.esdihumboldt.hale.io.csv/src/eu/esdihumboldt/hale/io/csv/writer/internal/CSVInstanceWriter.java b/io/plugins/eu.esdihumboldt.hale.io.csv/src/eu/esdihumboldt/hale/io/csv/writer/internal/CSVInstanceWriter.java index 89bcde0b94..0a120fd6df 100644 --- a/io/plugins/eu.esdihumboldt.hale.io.csv/src/eu/esdihumboldt/hale/io/csv/writer/internal/CSVInstanceWriter.java +++ b/io/plugins/eu.esdihumboldt.hale.io.csv/src/eu/esdihumboldt/hale/io/csv/writer/internal/CSVInstanceWriter.java @@ -177,13 +177,13 @@ private void addCSVFileByQName(IOReporter reporter, OutputStream outputStream, // try to be sure resources are all closed after try-block try (CSVWriter writer = new CSVWriter( new OutputStreamWriter(new FileOutputStream(tempFile)), sep, quote, esc);) { - writeLine(solveNestedProperties, headerRow, instance, writer); + writeLine(solveNestedProperties, headerRow, instance, writer, reporter); while (instanceIterator.hasNext()) { Instance nextInst = instanceIterator.next(); if (nextInst.getDefinition().equals(definition)) { - writeLine(solveNestedProperties, headerRow, nextInst, writer); + writeLine(solveNestedProperties, headerRow, nextInst, writer, reporter); } } } @@ -203,12 +203,12 @@ public boolean isPassthrough() { // write current instance to csv file private void writeLine(boolean solveNestedProperties, List headerRow, Instance instance, - CSVWriter writer) { + CSVWriter writer, IOReporter reporter) { boolean useSchema = getParameter(InstanceTableIOConstants.USE_SCHEMA).as(Boolean.class, true); List line = new ArrayList(); Map row = super.getPropertyMap(instance, headerRow, useSchema, - solveNestedProperties); + solveNestedProperties, reporter); for (String key : headerRow) { Object entry = row.get(key); line.add(getValueOfProperty(entry)); diff --git a/io/plugins/eu.esdihumboldt.hale.io.json.test/src/eu/esdihumboldt/hale/io/json/test/InstanceToJsonTest.groovy b/io/plugins/eu.esdihumboldt.hale.io.json.test/src/eu/esdihumboldt/hale/io/json/test/InstanceToJsonTest.groovy index 924a6c963b..63a1e60a6a 100644 --- a/io/plugins/eu.esdihumboldt.hale.io.json.test/src/eu/esdihumboldt/hale/io/json/test/InstanceToJsonTest.groovy +++ b/io/plugins/eu.esdihumboldt.hale.io.json.test/src/eu/esdihumboldt/hale/io/json/test/InstanceToJsonTest.groovy @@ -176,12 +176,10 @@ class InstanceToJsonTest { type: "Feature", "@type": "city", geometry: [ - type: "MultiPoint", + type: "Point", coordinates: [ - [ - 49.8728337, - 8.651 - ] + 49.8728337, + 8.651 ] ], properties: [ @@ -200,12 +198,10 @@ class InstanceToJsonTest { type: "Feature", "@type": "city", geometry: [ - type: "MultiPoint", + type: "Point", coordinates: [ - [ - 48.13722, - 11.5755 - ] + 48.13722, + 11.5755 ] ], properties: [ @@ -272,12 +268,10 @@ class InstanceToJsonTest { type: "Feature", "@type": "city", geometry: [ - type: "MultiPoint", + type: "Point", coordinates: [ - [ - 49.8728337891123, - 8.65122278912346 - ] + 49.8728337891123, + 8.65122278912346 ] ], properties: [ @@ -296,12 +290,10 @@ class InstanceToJsonTest { type: "Feature", "@type": "city", geometry: [ - type: "MultiPoint", + type: "Point", coordinates: [ - [ - 48.13722289876544, - 11.57555687654323 - ] + 48.13722289876544, + 11.57555687654323 ] ], properties: [ @@ -368,12 +360,10 @@ class InstanceToJsonTest { type: "Feature", "@type": "city", geometry: [ - type: "MultiPoint", + type: "Point", coordinates: [ - [ - 49.87283378911236, - 8.65122278912346 - ] + 49.87283378911236, + 8.65122278912346 ] ], properties: [ @@ -392,12 +382,10 @@ class InstanceToJsonTest { type: "Feature", "@type": "city", geometry: [ - type: "MultiPoint", + type: "Point", coordinates: [ - [ - 48.13722289876544, - 11.57555687654323 - ] + 48.13722289876544, + 11.57555687654323 ] ], properties: [ @@ -464,12 +452,10 @@ class InstanceToJsonTest { type: "Feature", "@type": "city", geometry: [ - type: "MultiPoint", + type: "Point", coordinates: [ - [ - 49.8728337891123, - 8.651222789123 - ] + 49.8728337891123, + 8.651222789123 ] ], properties: [ @@ -488,8 +474,8 @@ class InstanceToJsonTest { type: "Feature", "@type": "city", geometry: [ - type: "MultiPoint", - coordinates: [[48.137222, 11.575556]] + type: "Point", + coordinates: [48.137222, 11.575556] ], properties: [ population: 1471508, diff --git a/io/plugins/eu.esdihumboldt.hale.io.json/src/eu/esdihumboldt/hale/io/json/internal/InstanceToJson.java b/io/plugins/eu.esdihumboldt.hale.io.json/src/eu/esdihumboldt/hale/io/json/internal/InstanceToJson.java index f888aae72b..82ac222594 100644 --- a/io/plugins/eu.esdihumboldt.hale.io.json/src/eu/esdihumboldt/hale/io/json/internal/InstanceToJson.java +++ b/io/plugins/eu.esdihumboldt.hale.io.json/src/eu/esdihumboldt/hale/io/json/internal/InstanceToJson.java @@ -31,6 +31,7 @@ import org.geotools.geojson.geom.GeometryJSON; import org.geotools.geometry.jts.JTS; import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.GeometryCollection; import org.opengis.referencing.operation.MathTransform; import com.fasterxml.jackson.core.JsonFactory; @@ -652,6 +653,11 @@ protected void writeGeometryValue(JsonGenerator jsonGen, GeometryProperty geo geom = WindingOrder.unifyWindingOrder(geomProp.getGeometry(), true, geomProp.getCRSDefinition().getCRS()); + if (geomProp.getGeometry() instanceof GeometryCollection + && ((GeometryCollection) geomProp.getGeometry()).getNumGeometries() == 1) { + geom = geomProp.getGeometry().getGeometryN(0); + } + // FIXME what to do in case of an invalid geometry? jsonGen.writeRawValue(geometryJson.toString(geom)); diff --git a/io/plugins/eu.esdihumboldt.hale.io.xls/src/eu/esdihumboldt/hale/io/xls/writer/XLSInstanceWriter.java b/io/plugins/eu.esdihumboldt.hale.io.xls/src/eu/esdihumboldt/hale/io/xls/writer/XLSInstanceWriter.java index a2b5e82a35..244733bf36 100644 --- a/io/plugins/eu.esdihumboldt.hale.io.xls/src/eu/esdihumboldt/hale/io/xls/writer/XLSInstanceWriter.java +++ b/io/plugins/eu.esdihumboldt.hale.io.xls/src/eu/esdihumboldt/hale/io/xls/writer/XLSInstanceWriter.java @@ -111,7 +111,7 @@ else if (getContentType().getId().equals("eu.esdihumboldt.hale.io.xls.xlsx")) { for (TypeDefinition type : exportTypes) { // get all instances of the selected Type InstanceCollection instances = getInstances().select(new TypeFilter(type)); - addSheetByQName(type, instances); + addSheetByQName(type, instances, reporter); } try (FileOutputStream out = new FileOutputStream(getTarget().getLocation().getPath());) { @@ -156,7 +156,8 @@ else if (reporter != null) { * @param selectedTypeName selected QName * @param instances InstanceCollection available */ - private void addSheetByQName(TypeDefinition selectedTypeName, InstanceCollection instances) { + private void addSheetByQName(TypeDefinition selectedTypeName, InstanceCollection instances, + IOReporter reporter) { boolean solveNestedProperties = getParameter( InstanceTableIOConstants.SOLVE_NESTED_PROPERTIES).as(Boolean.class, false); @@ -179,7 +180,7 @@ private void addSheetByQName(TypeDefinition selectedTypeName, InstanceCollection if (!ignoreEmptyFeaturetypes) { Sheet sheet = workbook.createSheet(selectedTypeName.getDisplayName()); Row headerRow = sheet.createRow(0); - super.getPropertyMap(selectedTypeName, headerRowStrings); + super.getPropertyMap(selectedTypeName, headerRowStrings, reporter); writeHeaderRow(headerRow, headerRowStrings); setCellStyle(sheet, headerRowStrings.size()); resizeSheet(sheet); @@ -200,14 +201,14 @@ private void addSheetByQName(TypeDefinition selectedTypeName, InstanceCollection int rowNum = 1; Row row = sheet.createRow(rowNum++); writeRow(row, super.getPropertyMap(instance, headerRowStrings, useSchema, - solveNestedProperties), headerRowStrings); + solveNestedProperties, reporter), headerRowStrings); while (instanceIterator.hasNext()) { Instance nextInst = instanceIterator.next(); if (nextInst.getDefinition().equals(definition)) { row = sheet.createRow(rowNum++); writeRow(row, super.getPropertyMap(nextInst, headerRowStrings, useSchema, - solveNestedProperties), headerRowStrings); + solveNestedProperties, reporter), headerRowStrings); } }