Revision: 5663 http://sourceforge.net/p/jump-pilot/code/5663 Author: edso Date: 2018-01-04 18:09:57 +0000 (Thu, 04 Jan 2018) Log Message: ----------- JML/GML Reader/Writer add EPSG SRID support via WFS gml:boundedBy->gml:Box tag JML/GML Reader - add SAX Locator support to have errors sport line numbers/columns - reordered parsing methods into a meaningful order - reverted to BasicFeature/FeatureSchema until Schema editing via plugin is finished for FlexibleSchema JML/GML Writer - minimized space indention for better readability and to save disk space - is now cancelable via TaskMonitor button - reports feature count written so far now
Modified Paths: -------------- core/trunk/src/com/vividsolutions/jump/io/GMLInputTemplate.java core/trunk/src/com/vividsolutions/jump/io/GMLReader.java core/trunk/src/com/vividsolutions/jump/io/GMLWriter.java Modified: core/trunk/src/com/vividsolutions/jump/io/GMLInputTemplate.java =================================================================== --- core/trunk/src/com/vividsolutions/jump/io/GMLInputTemplate.java 2018-01-04 18:05:26 UTC (rev 5662) +++ core/trunk/src/com/vividsolutions/jump/io/GMLInputTemplate.java 2018-01-04 18:09:57 UTC (rev 5663) @@ -66,6 +66,7 @@ boolean loaded = false; String collectionTag; String featureTag; + String crsTag; ArrayList<ColumnDescription> columnDefinitions = new ArrayList<>(); //list of type ColumnDescription private XMLReader xr; @@ -75,6 +76,7 @@ private boolean havecollectionTag = false; private boolean havefeatureTag = false; private boolean havegeometryElement = false; + private boolean havecrsTag = false; //for the jcs column definition private int columnDef_valueType = 0; // 0 - undef, 1 = body, 2 = attribute @@ -550,6 +552,14 @@ return; } + if (qName.equalsIgnoreCase("CRSElement")) { + tagBody = tagBody.trim(); + crsTag = tagBody; + havecrsTag = true; + + return; + } + if (qName.equalsIgnoreCase("name")) { columnDef_columnName = tagBody.trim(); } Modified: core/trunk/src/com/vividsolutions/jump/io/GMLReader.java =================================================================== --- core/trunk/src/com/vividsolutions/jump/io/GMLReader.java 2018-01-04 18:05:26 UTC (rev 5662) +++ core/trunk/src/com/vividsolutions/jump/io/GMLReader.java 2018-01-04 18:09:57 UTC (rev 5663) @@ -44,6 +44,7 @@ import org.xml.sax.Attributes; import org.xml.sax.InputSource; +import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.XMLReader; @@ -58,12 +59,15 @@ import com.vividsolutions.jts.geom.Polygon; import com.vividsolutions.jts.geom.PrecisionModel; import com.vividsolutions.jump.I18N; +import com.vividsolutions.jump.coordsys.CoordinateSystem; import com.vividsolutions.jump.feature.AttributeType; +import com.vividsolutions.jump.feature.BasicFeature; import com.vividsolutions.jump.feature.Feature; import com.vividsolutions.jump.feature.FeatureCollection; import com.vividsolutions.jump.feature.FeatureDataset; -import com.vividsolutions.jump.feature.FlexibleFeature; -import com.vividsolutions.jump.feature.FlexibleFeatureSchema; +import com.vividsolutions.jump.feature.FeatureSchema; +//import com.vividsolutions.jump.feature.FlexibleFeature; +//import com.vividsolutions.jump.feature.FlexibleFeatureSchema; import com.vividsolutions.jump.task.DummyTaskMonitor; import com.vividsolutions.jump.task.TaskMonitor; import com.vividsolutions.jump.task.TaskMonitorSupport; @@ -246,7 +250,8 @@ public class GMLReader extends DefaultHandler implements JUMPReader, TaskMonitorSupport { private static int STATE_GET_COLUMNS = 3; - private Collection<Exception> exceptions; + private Collection<Exception> exceptions = new ArrayList<Exception>(); + private Locator locator; /** * STATE MEANING <br> @@ -263,6 +268,7 @@ private static int STATE_PARSE_GEOM_SIMPLE = 4; private static int STATE_WAIT_COLLECTION_TAG = 1; private static int STATE_WAIT_FEATURE_TAG = 2; + private static int STATE_WAIT_CRS_TAG = 8; private final static List<String> simpleGeoms = new ArrayList<>(); private final static List<String> multiGeoms = new ArrayList<>(); @@ -283,9 +289,9 @@ private int STATE = STATE_INIT; // list of points private Point apoint; private Feature currentFeature; - private int currentGeometryNumb = 1; +// private int currentGeometryNumb = 1; private FeatureCollection fc; - private FlexibleFeatureSchema fcmd; // list of geometries + private FeatureSchema fcmd; // list of geometries private Geometry finalGeometry; // list of geometrycollections - list of list of // geometry private String current_geom_qname = ""; @@ -346,6 +352,11 @@ xr.setErrorHandler(this); } + // get current location for throw errors + public void setDocumentLocator(Locator locator) { + this.locator = locator; + } + /** * parse SRID information in geometry tags * @@ -395,261 +406,23 @@ } } - /** - * SAX HANDLER - move to state 0 - */ - public void endDocument() { - // System.out.println("End document"); - STATE = STATE_INIT; - } - /** - * SAX handler - handle state information and transitions based on ending - * elements Most of the work of the parser is done here. - * - * @param uri - * Description of the Parameter - * @param name - * Description of the Parameter - * @param qName - * Description of the Parameter - * @exception SAXException - * Description of the Exception - */ - public void endElement(String uri, String name, String qName) - throws SAXException { - - // allow cancellation - if (getTaskMonitor().isCancelRequested()) throw new SAXCancelledException(); - - try { - int index; - // System.out.println("End element: " + qName); - if (STATE == STATE_INIT) { - tagBody = new StringBuffer(); - return; // something wrong - } - if (STATE > STATE_GET_COLUMNS) { - if (isMultiGeometryTag(qName)) { - if (STATE == STATE_PARSE_GEOM_NESTED) { - STATE = STATE_PARSE_GEOM_SIMPLE; // finished - no action. geometry - // is correct - } else { - // build the geometry that was in that collection - Geometry g; + private boolean compareToIgnoreCaseWithOptionalGmlColonPrefix( String value1, String value2 ){ + if (value1.equalsIgnoreCase(value2)) + return true; - g = geometryFactory.buildGeometry(geometry); - geometry = (ArrayList) recursivegeometry.get(STATE - - STATE_PARSE_GEOM_NESTED - 1); - geometry.add(g); - recursivegeometry.remove(STATE - STATE_PARSE_GEOM_NESTED); - g = null; - - STATE--; - } - } - - //System.out.println("wrap-element: " + qName); - // finalize geometry and add to feature - if (GMLinput.isGeometryElement(qName)) { - tagBody = new StringBuffer(); - STATE = STATE_GET_COLUMNS; - - // -- [sstein] 14.March.2009 - // read LinearRings even if we don't have polygons - if ( linearRing != null ) { - geometry.add(linearRing); - linearRing = null; - } - - if (regex_geomMultiPoint.matcher(current_geom_qname).matches()) - finalGeometry = geometryFactory - .createMultiPoint(geometry.toArray(new Point[0])); - else if (regex_geomMultiLineString.matcher(current_geom_qname).matches()) - finalGeometry = geometryFactory - .createMultiLineString((geometry.toArray(new LineString[0]))); - else if (regex_geomMultiPolygon.matcher(current_geom_qname).matches()) - finalGeometry = geometryFactory - .createMultiPolygon((geometry.toArray(new Polygon[0]))); -// else if (current_geom_qname.matches("^(?i)(gml:)?linearring$")) -// finalGeometry = (Geometry) geometry.get(0); - else - finalGeometry = geometryFactory.buildGeometry(geometry); - - // System.out.println("end geom: "+finalGeometry.toString() ); - currentFeature.setGeometry(finalGeometry); - currentGeometryNumb++; - - // reset multi qname - current_geom_qname = ""; - return; - } - - - //System.out.println("geom-element: " + qName); - // these correspond to <coord><X>0.0</X><Y>0.0</Y></coord> - if ((qName.compareToIgnoreCase("X") == 0) - || (qName.compareToIgnoreCase("gml:X") == 0)) { - singleCoordinate.x = Double.parseDouble(tagBody.toString()); - } else if ((qName.compareToIgnoreCase("Y") == 0) - || (qName.compareToIgnoreCase("gml:y") == 0)) { - singleCoordinate.y = Double.parseDouble(tagBody.toString()); - } else if ((qName.compareToIgnoreCase("Z") == 0) - || (qName.compareToIgnoreCase("gml:z") == 0)) { - singleCoordinate.z = Double.parseDouble(tagBody.toString()); - } else if ((qName.compareToIgnoreCase("COORD") == 0) - || (qName.compareToIgnoreCase("gml:coord") == 0)) { - pointList.add(new Coordinate(singleCoordinate)); // remember it - } - // this corresponds to - // <gml:coordinates>1195156.78946687,382069.533723461</gml:coordinates> - else if ((qName.compareToIgnoreCase("COORDINATES") == 0) - || (qName.compareToIgnoreCase("gml:coordinates") == 0)) { - // tagBody has a wack-load of points in it - we need - // to parse them into the pointList list. - // assume that the x,y,z coordinate are "," separated, and the points - // are " " separated - parsePoints(tagBody.toString(), geometryFactory); - } else if ((qName.compareToIgnoreCase("linearring") == 0) - || (qName.compareToIgnoreCase("gml:linearring") == 0)) { - Coordinate[] c = new Coordinate[0]; - - c = pointList.toArray(c); - - linearRing = geometryFactory.createLinearRing(c); - } else if ((qName.compareToIgnoreCase("outerBoundaryIs") == 0) - || (qName.compareToIgnoreCase("gml:outerBoundaryIs") == 0)) { - outerBoundary = linearRing; - linearRing = null; - } else if ((qName.compareToIgnoreCase("innerBoundaryIs") == 0) - || (qName.compareToIgnoreCase("gml:innerBoundaryIs") == 0)) { - innerBoundaries.add(linearRing); - linearRing = null; - } else if ((qName.compareToIgnoreCase("polygon") == 0) - || (qName.compareToIgnoreCase("gml:polygon") == 0)) { - // LinearRing[] lrs = new LinearRing[1]; - LinearRing[] lrs = new LinearRing[0]; - lrs = innerBoundaries.toArray(lrs); - polygon = geometryFactory.createPolygon(outerBoundary, lrs); - geometry.add(polygon); - } else if ((qName.compareToIgnoreCase("linestring") == 0) - || (qName.compareToIgnoreCase("gml:linestring") == 0)) { - Coordinate[] c = new Coordinate[0]; - - c = pointList.toArray(c); - - lineString = geometryFactory.createLineString(c); - geometry.add(lineString); - } else if ((qName.compareToIgnoreCase("point") == 0) - || (qName.compareToIgnoreCase("gml:point") == 0)) { - apoint = geometryFactory - .createPoint(pointList.size() > 0 ? pointList.get(0) : null); - geometry.add(apoint); - } - } else if (STATE == STATE_GET_COLUMNS) { - if (qName.compareToIgnoreCase(GMLinput.featureTag) == 0) { - tagBody = new StringBuffer(); - STATE = STATE_WAIT_FEATURE_TAG; - - // System.out.println("end feature"); - // create a feature and put it inside the featurecollection - if (currentFeature.getGeometry() == null) { - Geometry g = currentFeature.getGeometry(); - - if (g != null) { - //System.out.println(g.toString()); - } - - throw new ParseException("no geometry specified in feature"); - } - - fc.add(currentFeature); - report(fc.size()); - - currentFeature = null; - - return; - } else { - // check to see if this was a tag we want to store as a column - // DB: added 2nd check for GML like <a><b></b></a> - // the "b" tag is the "lastStartTag_qName" for "</b>" and "</a>" we - // only need to - // process it once. - try { - if (((index = GMLinput.match(lastStartTag_qName, lastStartTag_atts)) > -1) - && (lastStartTag_qName.equalsIgnoreCase(qName))) { - // System.out.println("value of " + - // GMLinput.columnName(index)+" : " + - // GMLinput.getColumnValue(index,tagBody, lastStartTag_atts) ); - - // if the column already has a value and multiItems support is - // turned on ..and its type ==object - if ((multiItemsAsLists) - && (currentFeature.getAttribute(GMLinput.columnName(index)) != null) - && (((ColumnDescription) (GMLinput.columnDefinitions - .get(index))).type == AttributeType.OBJECT)) { - Object oldValue = currentFeature.getAttribute(GMLinput - .columnName(index)); - if (oldValue instanceof List) { - // already a list there - just stuff another thing in! - ((List) oldValue).add(GMLinput.getColumnValue(index, - tagBody.toString(), lastStartTag_atts)); - } else { - // no list currently there - make a list and replace - List l = new ArrayList(); - l.add(oldValue); - l.add(GMLinput.getColumnValue(index, tagBody.toString(), - lastStartTag_atts)); // new value - currentFeature.setAttribute(GMLinput.columnName(index), l); - } - } else // handle normally - { - currentFeature.setAttribute(GMLinput.columnName(index), - GMLinput.getColumnValue(index, tagBody.toString(), - lastStartTag_atts)); - } - } - } catch (Exception e) { - // dont actually do anything with the parse problem - just ignore - // it, - // we cannot send it back because the function its overiding doesnt - // allow - e.printStackTrace(); - } - - tagBody = new StringBuffer(); - } - } else if (STATE == STATE_WAIT_FEATURE_TAG) { - if (qName.compareToIgnoreCase(GMLinput.collectionTag) == 0) { - STATE = STATE_INIT; // finish - - // System.out.println("DONE!"); - tagBody = new StringBuffer(); - - return; - } - } else if (STATE == STATE_WAIT_COLLECTION_TAG) { - tagBody = new StringBuffer(); - - return; // still look for start collection tag - } - } catch (Exception e) { - e.printStackTrace(); - throw new SAXException(e.getMessage()); - } + // retry making sure both are prefixed + String prefix = "gml:"; + if (!value1.toLowerCase().startsWith(prefix)) + value1 = prefix + value1; + if (!value2.toLowerCase().startsWith(prefix)) + value2 = prefix + value2; + return value1.equalsIgnoreCase(value2); } - public void error(SAXParseException exception) throws SAXException { - throw exception; - } - - public void fatalError(SAXParseException exception) throws SAXException { - throw exception; - } - /** * Main Entry - load in a GML file * @@ -847,7 +620,7 @@ if (getTaskMonitor().isCancelRequested()) throw new SAXCancelledException(); try { - // System.out.println("Start element: " + qName); + //System.out.println("Start element: " + qName); tagBody = new StringBuffer(); lastStartTag_uri = uri; lastStartTag_name = name; @@ -854,6 +627,9 @@ lastStartTag_qName = qName; lastStartTag_atts = atts; +// if (STATE == STATE_WAIT_COLLECTION_TAG) +// System.out.println("(STATE == STATE_WAIT_COLLECTION_TAG)"); + if (STATE == STATE_INIT) { return; // something wrong } @@ -866,17 +642,47 @@ return; } + + if ((STATE == STATE_WAIT_FEATURE_TAG) + && compareToIgnoreCaseWithOptionalGmlColonPrefix(qName, GMLinput.crsTag) ) { + // found the crs1 tag + return; + } + if ((STATE == STATE_WAIT_FEATURE_TAG) + && compareToIgnoreCaseWithOptionalGmlColonPrefix(qName, "Box") ) { + // found the crs2 box tag + + // fetch srid id + for (int i = 0; i < atts.getLength(); i++) { + String attName = atts.getQName(i); + if (attName.equalsIgnoreCase("srsName")){ + String attValue = atts.getValue(i); + String sridString = attValue.substring(attValue.lastIndexOf("#") + 1); + + try { + SRID = Integer.valueOf(sridString); + } catch (NumberFormatException e) { + addParseException("srid '"+sridString+"'is not a number.", e); + } + } + } + STATE = STATE_WAIT_FEATURE_TAG; + + return; + } + + if ((STATE == STATE_WAIT_FEATURE_TAG) && (qName.compareToIgnoreCase(GMLinput.featureTag) == 0)) { // found the feature tag // System.out.println("found feature"); - currentFeature = new FlexibleFeature(fcmd); + currentFeature = new BasicFeature(fcmd); STATE = STATE_GET_COLUMNS; - SRID = 0;// default SRID (reset for each feature, but should be constant - // for a featurecollection) - if (geometryFactory.getSRID() != SRID) - geometryFactory = new GeometryFactory(new PrecisionModel(), SRID); +// SRID = 0;// default SRID (reset for each feature, but should be constant +// // for a featurecollection) +// if (geometryFactory.getSRID() != SRID) +// geometryFactory = new GeometryFactory(new PrecisionModel(), SRID); return; } @@ -956,14 +762,281 @@ } } catch (Exception e) { + e.printStackTrace(System.err); throw new SAXException(e.getMessage()); } } + /** + * SAX handler - handle state information and transitions based on ending + * elements Most of the work of the parser is done here. + * + * @param uri + * Description of the Parameter + * @param name + * Description of the Parameter + * @param qName + * Description of the Parameter + * @exception SAXException + * Description of the Exception + */ + public void endElement(String uri, String name, String qName) + throws SAXException { + + // allow cancellation + if (getTaskMonitor().isCancelRequested()) throw new SAXCancelledException(); + + try { + int index; + + // System.out.println("End element: " + qName); + if (STATE == STATE_INIT) { + tagBody = new StringBuffer(); + + return; // something wrong + } + + if (STATE > STATE_GET_COLUMNS) { + if (isMultiGeometryTag(qName)) { + if (STATE == STATE_PARSE_GEOM_NESTED) { + STATE = STATE_PARSE_GEOM_SIMPLE; // finished - no action. geometry + // is correct + } else { + // build the geometry that was in that collection + Geometry g; + + g = geometryFactory.buildGeometry(geometry); + geometry = (ArrayList) recursivegeometry.get(STATE + - STATE_PARSE_GEOM_NESTED - 1); + geometry.add(g); + recursivegeometry.remove(STATE - STATE_PARSE_GEOM_NESTED); + g = null; + + STATE--; + } + } + + //System.out.println("wrap-element: " + qName); + // finalize geometry and add to feature + if (GMLinput.isGeometryElement(qName)) { + tagBody = new StringBuffer(); + STATE = STATE_GET_COLUMNS; + + // -- [sstein] 14.March.2009 + // read LinearRings even if we don't have polygons + if ( linearRing != null ) { + geometry.add(linearRing); + linearRing = null; + } + + if (regex_geomMultiPoint.matcher(current_geom_qname).matches()) + finalGeometry = geometryFactory + .createMultiPoint(geometry.toArray(new Point[0])); + else if (regex_geomMultiLineString.matcher(current_geom_qname).matches()) + finalGeometry = geometryFactory + .createMultiLineString((geometry.toArray(new LineString[0]))); + else if (regex_geomMultiPolygon.matcher(current_geom_qname).matches()) + finalGeometry = geometryFactory + .createMultiPolygon((geometry.toArray(new Polygon[0]))); +// else if (current_geom_qname.matches("^(?i)(gml:)?linearring$")) +// finalGeometry = (Geometry) geometry.get(0); + else + finalGeometry = geometryFactory.buildGeometry(geometry); + + // System.out.println("end geom: "+finalGeometry.toString() ); + currentFeature.setGeometry(finalGeometry); +// currentGeometryNumb++; + + // reset multi qname + current_geom_qname = ""; + return; + } + + + //System.out.println("geom-element: " + qName); + // these correspond to <coord><X>0.0</X><Y>0.0</Y></coord> + if ((qName.compareToIgnoreCase("X") == 0) + || (qName.compareToIgnoreCase("gml:X") == 0)) { + singleCoordinate.x = Double.parseDouble(tagBody.toString()); + } else if ((qName.compareToIgnoreCase("Y") == 0) + || (qName.compareToIgnoreCase("gml:y") == 0)) { + singleCoordinate.y = Double.parseDouble(tagBody.toString()); + } else if ((qName.compareToIgnoreCase("Z") == 0) + || (qName.compareToIgnoreCase("gml:z") == 0)) { + singleCoordinate.z = Double.parseDouble(tagBody.toString()); + } else if ((qName.compareToIgnoreCase("COORD") == 0) + || (qName.compareToIgnoreCase("gml:coord") == 0)) { + pointList.add(new Coordinate(singleCoordinate)); // remember it + } + // this corresponds to + // <gml:coordinates>1195156.78946687,382069.533723461</gml:coordinates> + else if ((qName.compareToIgnoreCase("COORDINATES") == 0) + || (qName.compareToIgnoreCase("gml:coordinates") == 0)) { + // tagBody has a wack-load of points in it - we need + // to parse them into the pointList list. + // assume that the x,y,z coordinate are "," separated, and the points + // are " " separated + parsePoints(tagBody.toString(), geometryFactory); + } else if ((qName.compareToIgnoreCase("linearring") == 0) + || (qName.compareToIgnoreCase("gml:linearring") == 0)) { + Coordinate[] c = new Coordinate[0]; + + c = pointList.toArray(c); + + linearRing = geometryFactory.createLinearRing(c); + } else if ((qName.compareToIgnoreCase("outerBoundaryIs") == 0) + || (qName.compareToIgnoreCase("gml:outerBoundaryIs") == 0)) { + outerBoundary = linearRing; + linearRing = null; + } else if ((qName.compareToIgnoreCase("innerBoundaryIs") == 0) + || (qName.compareToIgnoreCase("gml:innerBoundaryIs") == 0)) { + innerBoundaries.add(linearRing); + linearRing = null; + } else if ((qName.compareToIgnoreCase("polygon") == 0) + || (qName.compareToIgnoreCase("gml:polygon") == 0)) { + // LinearRing[] lrs = new LinearRing[1]; + LinearRing[] lrs = new LinearRing[0]; + lrs = innerBoundaries.toArray(lrs); + polygon = geometryFactory.createPolygon(outerBoundary, lrs); + geometry.add(polygon); + } else if ((qName.compareToIgnoreCase("linestring") == 0) + || (qName.compareToIgnoreCase("gml:linestring") == 0)) { + Coordinate[] c = new Coordinate[0]; + + c = pointList.toArray(c); + + lineString = geometryFactory.createLineString(c); + geometry.add(lineString); + } else if ((qName.compareToIgnoreCase("point") == 0) + || (qName.compareToIgnoreCase("gml:point") == 0)) { + apoint = geometryFactory + .createPoint(pointList.size() > 0 ? pointList.get(0) : null); + geometry.add(apoint); + } + } else if (STATE == STATE_GET_COLUMNS) { + if (qName.compareToIgnoreCase(GMLinput.featureTag) == 0) { + tagBody = new StringBuffer(); + STATE = STATE_WAIT_FEATURE_TAG; + + // System.out.println("end feature"); + // create a feature and put it inside the featurecollection + if (currentFeature.getGeometry() == null) { + Geometry g = currentFeature.getGeometry(); + + if (g != null) { + //System.out.println(g.toString()); + } + + throw new ParseException("no geometry specified in feature"); + } + + fc.add(currentFeature); + report(fc.size()); + + currentFeature = null; + + return; + } else { + // check to see if this was a tag we want to store as a column + // DB: added 2nd check for GML like <a><b></b></a> + // the "b" tag is the "lastStartTag_qName" for "</b>" and "</a>" we + // only need to + // process it once. + try { + if (((index = GMLinput.match(lastStartTag_qName, lastStartTag_atts)) > -1) + && (lastStartTag_qName.equalsIgnoreCase(qName))) { + // System.out.println("value of " + + // GMLinput.columnName(index)+" : " + + // GMLinput.getColumnValue(index,tagBody, lastStartTag_atts) ); + + // if the column already has a value and multiItems support is + // turned on ..and its type ==object + if ((multiItemsAsLists) + && (currentFeature.getAttribute(GMLinput.columnName(index)) != null) + && (((ColumnDescription) (GMLinput.columnDefinitions + .get(index))).type == AttributeType.OBJECT)) { + Object oldValue = currentFeature.getAttribute(GMLinput + .columnName(index)); + if (oldValue instanceof List) { + // already a list there - just stuff another thing in! + ((List) oldValue).add(GMLinput.getColumnValue(index, + tagBody.toString(), lastStartTag_atts)); + } else { + // no list currently there - make a list and replace + List l = new ArrayList(); + l.add(oldValue); + l.add(GMLinput.getColumnValue(index, tagBody.toString(), + lastStartTag_atts)); // new value + currentFeature.setAttribute(GMLinput.columnName(index), l); + } + } else // handle normally + { + currentFeature.setAttribute(GMLinput.columnName(index), + GMLinput.getColumnValue(index, tagBody.toString(), + lastStartTag_atts)); + } + } + } catch (Exception e) { + // dont actually do anything with the parse problem - just ignore + // it, + // we cannot send it back because the function its overiding doesnt + // allow + e.printStackTrace(); + } + + tagBody = new StringBuffer(); + } + } else if (STATE == STATE_WAIT_FEATURE_TAG) { + if (qName.compareToIgnoreCase(GMLinput.collectionTag) == 0) { + STATE = STATE_INIT; // finish + + // System.out.println("DONE!"); + tagBody = new StringBuffer(); + + return; + } + } else if (STATE == STATE_WAIT_COLLECTION_TAG) { + tagBody = new StringBuffer(); + + return; // still look for start collection tag + } else if (STATE == STATE_WAIT_CRS_TAG) { + if (compareToIgnoreCaseWithOptionalGmlColonPrefix(qName, "Box")) { + STATE = STATE_WAIT_COLLECTION_TAG; + } + return; // still looking for <gml:Box/> + } + + + } catch (Exception e) { + e.printStackTrace(); + throw new SAXException(e.getMessage()); + } + } + + /** + * SAX HANDLER - move to state 0 + */ + public void endDocument() { + // System.out.println("End document"); + + // apply srid if not unset + if (SRID > 0) + fc.getFeatureSchema().setCoordinateSystem(new CoordinateSystem("", SRID, null)); + STATE = STATE_INIT; + } + // ////////////////////////////////////////////////////////////////// // Error handlers. // ////////////////////////////////////////////////////////////////// public void warning(SAXParseException exception) throws SAXException { + exceptions.add(exception); + } + + public void error(SAXParseException exception) throws SAXException { + exceptions.add(exception); + } + + public void fatalError(SAXParseException exception) throws SAXException { throw exception; } @@ -1111,19 +1184,26 @@ int semicolonLoc = srsName.lastIndexOf(':'); if (semicolonLoc == -1) return 0; - srsName = srsName.substring(semicolonLoc + 1).trim(); - return Integer.parseInt(srsName); - } catch (Exception e) { + return Integer.parseInt(srsName.substring(semicolonLoc + 1).trim()); + } catch (NumberFormatException e) { + addParseException( "srid '"+srsName+"'is not a number.", e); return 0; } } + protected void addException(Exception e){ + exceptions.add(e); + } + + protected void addParseException(String message, Exception cause) { + exceptions.add( + new ParseException(message, streamName, locator.getLineNumber(), locator.getColumnNumber(), cause)); + } + /** * @return exceptions collected during the reading process. */ public Collection<Exception> getExceptions() { - if (exceptions == null) - exceptions = new ArrayList<>(); return exceptions; } Modified: core/trunk/src/com/vividsolutions/jump/io/GMLWriter.java =================================================================== --- core/trunk/src/com/vividsolutions/jump/io/GMLWriter.java 2018-01-04 18:05:26 UTC (rev 5662) +++ core/trunk/src/com/vividsolutions/jump/io/GMLWriter.java 2018-01-04 18:09:57 UTC (rev 5663) @@ -37,6 +37,7 @@ import java.io.FileReader; import java.io.OutputStreamWriter; import java.io.Writer; +import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; @@ -44,11 +45,19 @@ import org.apache.commons.lang3.StringEscapeUtils; +import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.util.Assert; +import com.vividsolutions.jump.I18N; +import com.vividsolutions.jump.coordsys.CoordinateSystem; import com.vividsolutions.jump.feature.AttributeType; import com.vividsolutions.jump.feature.Feature; import com.vividsolutions.jump.feature.FeatureCollection; import com.vividsolutions.jump.feature.FeatureSchema; +import com.vividsolutions.jump.task.DummyTaskMonitor; +import com.vividsolutions.jump.task.TaskMonitor; +import com.vividsolutions.jump.task.TaskMonitorSupport; +import com.vividsolutions.jump.task.TaskMonitorUtil; +import com.vividsolutions.jump.util.Timer; /** @@ -109,18 +118,18 @@ * </pre> * */ -public class GMLWriter implements JUMPWriter { +public class GMLWriter implements JUMPWriter, TaskMonitorSupport { // Standard tags for the auto-generated outputTemplate. - private static String standard_geom = "geometry"; - private static String standard_feature = "feature"; - private static String standard_featureCollection = "featureCollection"; + private static final String standard_geom = "geometry"; + private static final String standard_feature = "feature"; + private static final String standard_featureCollection = "featureCollection"; private GMLOutputTemplate outputTemplate = null; private GMLGeometryWriter geometryWriter = new GMLGeometryWriter(); /** constructor**/ public GMLWriter() { - geometryWriter.setLinePrefix(" "); + geometryWriter.setLinePrefix(" "); } /** @@ -146,7 +155,7 @@ if (dp.getProperty("TemplateFile") == null) { //we're going create the output template - gmlTemplate = GMLWriter.makeOutputTemplate(featureCollection.getFeatureSchema()); + gmlTemplate = makeOutputTemplate(featureCollection); } else { // load the template java.io.Reader r; @@ -192,7 +201,29 @@ buffWriter.write(outputTemplate.headerText); - for (Iterator t = featureCollection.iterator(); t.hasNext();) { + // write a bounded by box definition setting an srid for the whole dataset + // Workaround or convenience as OGC writes in the WFS 2.0 standard: + // 11.3.6 Inheritance rules for srsName values + if (getSrid(featureCollection) > 0){ + Envelope env = featureCollection.getEnvelope(); + DecimalFormat df = new DecimalFormat("#,##0.00"); + df.setGroupingUsed(false); + String envString = df.format(env.getMinX()) + "," + df.format(env.getMinY()) + " " + df.format(env.getMaxX()) + + "," + df.format(env.getMaxY()); + buffWriter.write( + " <gml:boundedBy>\n" + + " <gml:Box srsName=\"http://www.opengis.net/gml/srs/epsg.xml#"+getSrid(featureCollection)+"\">\n" + + " <gml:coordinates decimal=\".\" cs=\",\" ts=\" \">" + envString + "</gml:coordinates>\n" + + " </gml:Box>\n" + + " </gml:boundedBy>\n"); + } + + long milliSeconds = 0; + int count = 0; + int size = featureCollection.size(); + TaskMonitorUtil.report(getTaskMonitor(), + I18N.getMessage("Writer.writing-features")); + for (Iterator t = featureCollection.iterator(); t.hasNext() && !getTaskMonitor().isCancelRequested();) { f = (Feature) t.next(); for (int u = 0; u < outputTemplate.featureText.size(); u++) { @@ -207,6 +238,14 @@ buffWriter.write(outputTemplate.featureTextfooter); buffWriter.write("\n"); + + long now = Timer.milliSecondsSince(0); + count++; + // show status every .5s + if (now - 500 >= milliSeconds) { + milliSeconds = now; + TaskMonitorUtil.report(getTaskMonitor(), count, size, ""); + } } buffWriter.write(outputTemplate.footerText); @@ -224,41 +263,22 @@ // this should take care of really _all_ XML1.0 invalid chars // see https://commons.apache.org/proper/commons-lang/javadocs/api-3.5/org/apache/commons/lang3/StringEscapeUtils.html#escapeXml10-java.lang.String- return StringEscapeUtils.escapeXml10(s); + } - - // kept for reference -// StringBuilder sb = new StringBuilder(s); -// char c; -// -// for (int t = 0; t < sb.length(); t++) { -// c = sb.charAt(t); -// -// if (c == '<') { -// sb.replace(t, t + 1, "<"); -// } -// -// if (c == '>') { -// sb.replace(t, t + 1, ">"); -// } -// -// if (c == '&') { -// sb.replace(t, t + 1, "&"); -// } -// -// if (c == '\'') { -// sb.replace(t, t + 1, "'"); -// } -// -// if (c == '"') { -// sb.replace(t, t + 1, """); -// } -// -// if ((int)c < 20 && c != '\t' && c != '\n' && c != '\r') { -// sb.replace(t, t + 1, ""); -// } -// } -// -// return sb.toString(); + /** + * utility function to retrieve srid from a feature collection or -1 if none + * + * @param featureCollection + * @return srid + */ + private static int getSrid( FeatureCollection featureCollection ){ + Integer srid = -1; + CoordinateSystem cs = featureCollection.getFeatureSchema().getCoordinateSystem(); + if (!cs.equals(CoordinateSystem.UNSPECIFIED)) { + srid = cs.getEPSGCode(); + } + + return srid.intValue(); } /** @@ -327,7 +347,7 @@ } // precompile pattern for performance reasons - Pattern closingTagPattern = Pattern.compile(">$"); + static Pattern closingTagPattern = Pattern.compile(">$"); private void evaluateToken(Feature f, String pre, String token, Writer writer) throws Exception { @@ -399,11 +419,11 @@ return attribute.toString(); } + private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + protected String format(Date date) { return dateFormatter.format(date); } - - private SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); /** * Given a FeatureSchema, make an output template @@ -410,7 +430,7 @@ * in the JCS format * @param fcmd input featureSchema */ - private static GMLOutputTemplate makeOutputTemplate(FeatureSchema fcmd) { + private static GMLOutputTemplate makeOutputTemplate(FeatureCollection fc) { GMLOutputTemplate result; String inputTemplate; int t; @@ -418,16 +438,17 @@ String colText; String colCode; String colHeader; + FeatureSchema fcmd = fc.getFeatureSchema(); result = new GMLOutputTemplate(); - inputTemplate = makeInputTemplate(fcmd); + inputTemplate = makeInputTemplate(fc); result.setHeaderText( "<?xml version='1.0' encoding='UTF-8'?>\n<JCSDataFile xmlns:gml=\"http://www.opengis.net/gml\" xmlns:xsi=\"http://www.w3.org/2000/10/XMLSchema-instance\" >\n" + inputTemplate + "<" + standard_featureCollection + ">\n"); - colHeader = " <" + standard_feature + "> \n"; + colHeader = " <" + standard_feature + "> \n"; for (t = 0; t < fcmd.getAttributeCount(); t++) { colName = fcmd.getAttributeName(t); @@ -434,23 +455,23 @@ if (t != fcmd.getGeometryIndex()) { //not geometry - colText = colHeader + " <property name=\"" + escapeXML(colName) + + colText = colHeader + " <property name=\"" + escapeXML(colName) + "\">"; colCode = "=column " + colName; colHeader = "</property>\n"; } else { //geometry - colText = colHeader + " <" + standard_geom + ">\n"; + colText = colHeader + " <" + standard_geom + ">\n"; colCode = "=geometry"; - colHeader = " </" + standard_geom + ">\n"; + colHeader = " </" + standard_geom + ">\n"; } result.addItem(colText, colCode); } - result.setFeatureFooter(colHeader + " </" + standard_feature + + result.setFeatureFooter(colHeader + " </" + standard_feature + ">\n"); - result.setFooterText(" </" + standard_featureCollection + + result.setFooterText(" </" + standard_featureCollection + ">\n</JCSDataFile>\n"); return result; @@ -463,15 +484,21 @@ * * @param fcmd the featureSchema to describe */ - private static String makeInputTemplate(FeatureSchema fcmd) { - String result; + private static String makeInputTemplate(FeatureCollection fc) { + String result = ""; int t; + FeatureSchema fcmd = fc.getFeatureSchema(); - result = "<JCSGMLInputTemplate>\n<CollectionElement>" + - standard_featureCollection + - "</CollectionElement> \n<FeatureElement>" + standard_feature + - "</FeatureElement>\n<GeometryElement>" + standard_geom + - "</GeometryElement>\n<ColumnDefinitions>\n"; + result += "<JCSGMLInputTemplate>\n"; + result += "<CollectionElement>" + standard_featureCollection + "</CollectionElement>\n"; + result += "<FeatureElement>" + standard_feature + "</FeatureElement>\n"; + result += "<GeometryElement>" + standard_geom + "</GeometryElement>\n"; + // write a bounded by box definition setting an srid for the whole dataset + // Workaround or convenience as OGC writes in the WFS 2.0 standard: + // 11.3.6 Inheritance rules for srsName values + if (getSrid(fc) > 0) + result += "<CRSElement>boundedBy</CRSElement>\n"; + result += "<ColumnDefinitions>\n"; //fill in each of the column defs for (t = 0; t < fcmd.getAttributeCount(); t++) { @@ -505,4 +532,14 @@ return result; } + + private TaskMonitor taskMonitor = new DummyTaskMonitor(); + + public void setTaskMonitor(TaskMonitor taskMonitor) { + this.taskMonitor = taskMonitor; + } + + public TaskMonitor getTaskMonitor() { + return taskMonitor; + } } ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Jump-pilot-devel mailing list Jump-pilot-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jump-pilot-devel