package org.openlca.jsonld.input;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
/**
* A minimal converter of GeoJSON to KML (as used in openLCA).
*
* @see https://developers.google.com/kml/documentation/kmlreference
* @see http://geojson.org/geojson-spec.html
*/
class GeoJson2Kml {
private XMLStreamWriter kml;
private int indent = 0;
private GeoJson2Kml(XMLStreamWriter kml) {
this.kml = kml;
}
static String convert(JsonObject geoJson) {
if (geoJson == null)
return null;
XMLOutputFactory fac = XMLOutputFactory.newInstance();
try (StringWriter writer = new StringWriter()) {
XMLStreamWriter kml = fac.createXMLStreamWriter(writer);
new GeoJson2Kml(kml).doIt(geoJson);
kml.flush();
writer.flush();
kml.close();
return writer.toString();
} catch (Exception e) {
Logger log = LoggerFactory.getLogger(GeoJson2Kml.class);
log.error("failed to convert GeoJSON", e);
return null;
}
}
private void doIt(JsonObject geoJson) throws Exception {
kml.writeStartDocument("utf-8", "1.0");
kml.setDefaultNamespace("http://earth.google.com/kml/2.0");
startElem("kml");
kml.writeNamespace("", "http://earth.google.com/kml/2.0");
startElems("Folder", "Placemark");
writeGeometry(geoJson);
endElems(3);
kml.writeEndDocument();
}
private void writeGeometry(JsonObject geoJson) throws Exception {
JsonElement typeElem = geoJson.get("type");
if (typeElem == null || !typeElem.isJsonPrimitive())
return;
String type = typeElem.getAsString();
switch (type) {
case "Point":
writePoint(geoJson);
break;
case "LineString":
writeLineString(geoJson);
break;
case "Polygon":
writePolygon(geoJson);
break;
case "GeometryCollection":
writeGeometryCollection(geoJson);
break;
}
}
private void writePoint(JsonObject geoJson) throws Exception {
String coordinate = getCoordinate(geoJson.get("coordinates"));
if (coordinate == null)
return;
startElems("Point", "coordinates");
writeCoordinate(coordinate);
endElem();
endElem();
}
private void writeLineString(JsonObject geoJson) throws Exception {
JsonElement elem = geoJson.get("coordinates");
List<String> coordinates = getCoordinates(elem);
if (coordinates.isEmpty())
return;
startElems("LineString", "coordinates");
for (String coordinate : coordinates)
writeCoordinate(coordinate);
endElems(2);
}
private void writePolygon(JsonObject geoJson) throws Exception {
JsonElement elem = geoJson.get("coordinates");
if (elem == null || !elem.isJsonArray())
return;
JsonArray array = elem.getAsJsonArray();
if (array.size() == 0)
return;
List<String> outerRing = getCoordinates(array.get(0));
if (outerRing.isEmpty())
return;
startElem("Polygon");
startElems("outerBoundaryIs", "LinearRing", "coordinates");
for (String coordinate : outerRing)
writeCoordinate(coordinate);
endElems(3);
if (array.size() > 1) {
List<String> innerRing = getCoordinates(array.get(1));
startElems("innerBoundaryIs", "LinearRing", "coordinates");
for (String coordinate : innerRing)
writeCoordinate(coordinate);
endElems(3);
}
endElem();
}
private void writeGeometryCollection(JsonObject geoJson) throws Exception {
JsonElement elem = geoJson.get("geometries");
if (elem == null || !elem.isJsonArray())
return;
startElem("MultiGeometry");
for (JsonElement geom : elem.getAsJsonArray()) {
if (!geom.isJsonObject())
continue;
writeGeometry(geom.getAsJsonObject());
}
endElem();
}
private void writeCoordinate(String coordinate) throws XMLStreamException {
kml.writeCharacters("\n");
for (int i = 0; i < indent; i++)
kml.writeCharacters(" ");
kml.writeCharacters(coordinate);
}
private List<String> getCoordinates(JsonElement elem) {
if (elem == null || !elem.isJsonArray())
return Collections.emptyList();
JsonArray array = elem.getAsJsonArray();
List<String> coordinates = new ArrayList<>();
for (JsonElement ce : array) {
String coordinate = getCoordinate(ce);
if (coordinate == null)
return Collections.emptyList();
coordinates.add(coordinate);
}
return coordinates;
}
private String getCoordinate(JsonElement elem) {
if (elem == null || !elem.isJsonArray())
return null;
JsonArray point = elem.getAsJsonArray();
StringBuilder s = new StringBuilder();
boolean first = true;
for (JsonElement num : point) {
if (!num.isJsonPrimitive())
return null;
if (!first)
s.append(',');
else
first = false;
double d = num.getAsDouble();
s.append(d);
}
return s.toString();
}
private void startElems(String... names) throws Exception {
for (String name : names)
startElem(name);
}
private void startElem(String name) throws Exception {
kml.writeCharacters("\n");
for (int i = 0; i < indent; i++)
kml.writeCharacters(" ");
kml.writeStartElement(name);
indent++;
}
private void endElems(int count) throws Exception {
for (int i = 0; i < count; i++)
endElem();
}
private void endElem() throws Exception {
kml.writeCharacters("\n");
indent--;
for (int i = 0; i < indent; i++)
kml.writeCharacters(" ");
kml.writeEndElement();
}
}