X-Git-Url: http://gitweb.fperrin.net/?p=GpsPrune.git;a=blobdiff_plain;f=src%2Ftim%2Fprune%2Fload%2Fxml%2FKmlHandler.java;fp=src%2Ftim%2Fprune%2Fload%2Fxml%2FKmlHandler.java;h=e8f2c6a463fab9d2d8eda416dacaa8e88fef175c;hp=0000000000000000000000000000000000000000;hb=ce6f2161b8596f7018d6a76bff79bc9e571f35fd;hpb=2d8cb72e84d5cc1089ce77baf1e34ea3ea2f8465 diff --git a/src/tim/prune/load/xml/KmlHandler.java b/src/tim/prune/load/xml/KmlHandler.java new file mode 100644 index 0000000..e8f2c6a --- /dev/null +++ b/src/tim/prune/load/xml/KmlHandler.java @@ -0,0 +1,302 @@ +package tim.prune.load.xml; + +import java.util.ArrayList; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +import tim.prune.data.Field; + + +/** + * Class for handling specifics of parsing Kml files + */ +public class KmlHandler extends XmlHandler +{ + private boolean _insideCoordinates = false; + private boolean _insideGxTrack = false; + private String _value = null; + private String _name = null, _desc = null; + private String _timestamp = null, _imgLink = null; + private StringBuffer _coordinates = null; + private ArrayList _coordinateList = null; + private ArrayList _pointList = new ArrayList(); + private ArrayList _linkList = new ArrayList(); + // variables for gx extensions + private ArrayList _whenList = new ArrayList(); + private ArrayList _whereList = new ArrayList(); + + + /** + * Receive the start of a tag + * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) + */ + public void startElement(String uri, String localName, String qName, + Attributes attributes) throws SAXException + { + String tagName = localName; + if (tagName == null || tagName.equals("")) {tagName = qName;} + tagName = tagName.toLowerCase(); + + if (tagName.equals("placemark")) + { + _coordinateList = new ArrayList(); + } + else if (tagName.equals("coordinates")) + { + _insideCoordinates = true; + _coordinates = null; + } + else if (tagName.equals("gx:track")) + { + _insideGxTrack = true; + } + _value = null; + super.startElement(uri, localName, qName, attributes); + } + + + /** + * Process end tag + * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String) + */ + public void endElement(String uri, String localName, String qName) + throws SAXException + { + String tagName = localName; + if (tagName == null || tagName.equals("")) {tagName = qName;} + tagName = tagName.toLowerCase(); + + if (tagName.equals("placemark")) + { + processPlacemark(); + _name = _desc = _imgLink = _timestamp = null; + } + else if (tagName.equals("coordinates")) + { + _insideCoordinates = false; + if (_coordinates != null) _coordinateList.add(_coordinates.toString().trim()); + } + else if (tagName.equals("name")) + { + _name = _value; + } + else if (tagName.equals("description")) + { + _desc = _value; + _imgLink = getImgLink(_desc); + } + else if (tagName.equals("when")) + { + if (!_insideGxTrack) + _timestamp = _value; + else + _whenList.add(_value); + } + else if (tagName.equals("gx:coord")) + { + if (_insideGxTrack) { + _whereList.add(_value); + } + } + else if (tagName.equals("gx:track")) + { + processGxTrack(); + _insideGxTrack = false; + } + super.endElement(uri, localName, qName); + } + + + /** + * Process character text (inside tags or between them) + * @see org.xml.sax.ContentHandler#characters(char[], int, int) + */ + public void characters(char[] ch, int start, int length) + throws SAXException + { + String val = new String(ch, start, length); + if (_insideCoordinates) + { + if (_coordinates == null) { + _coordinates = new StringBuffer(); + } + _coordinates.append(val); + } + else + { + // Store string in _value + if (_value == null) _value = val; + else _value = _value + val; + } + super.characters(ch, start, length); + } + + + /** + * Process a placemark entry, either a single waypoint or a whole track + */ + private void processPlacemark() + { + if (_coordinateList == null || _coordinateList.isEmpty()) return; + final boolean isSingleSelection = (_coordinateList.size() == 1); + // Loop over coordinate sets in list (may have multiple tags within single placemark) + for (String coords : _coordinateList) + { + String[] coordArray = coords.split("[ \n]"); + int numPoints = coordArray.length; + if (numPoints == 1) + { + // Add single point to list + final String name = (isSingleSelection ? _name : null); + _pointList.add(makeStringArray(coords, name, _desc, _timestamp)); + _linkList.add(_imgLink); + } + else if (numPoints > 1) + { + // Add each of the unnamed track points to list + boolean firstPoint = true; + for (int p=0; p3) + { + String[] pointArray = makeStringArray(coordArray[p], null, null, null); + if (firstPoint) {pointArray[5] = "1";} // start of segment flag + firstPoint = false; + _pointList.add(pointArray); + } + _linkList.add(null); + } + } + } + } + + /** + * Process a Gx track including timestamps + */ + private void processGxTrack() + { + if (!_whereList.isEmpty()) + { + // If the whens don't match, then throw them all away + if (_whenList.size() != _whereList.size()) {System.out.println("clearing!"); _whenList.clear();} + + // Add each of the unnamed track points to list + boolean firstPoint = true; + final int numPoints = _whenList.size(); + for (int p=0; p < numPoints; p++) + { + String when = (_whenList.isEmpty() ? null : _whenList.get(p)); + String where = _whereList.get(p); + if (where != null) + { + String[] coords = where.split(" "); + if (coords.length == 3) + { + String[] pointArray = new String[7]; + pointArray[0] = coords[0]; + pointArray[1] = coords[1]; + pointArray[2] = coords[2]; + // leave name and description empty + if (firstPoint) {pointArray[5] = "1";} // start of segment flag + firstPoint = false; + pointArray[6] = when; // timestamp + _pointList.add(pointArray); + } + } + _linkList.add(null); + } + } + _whenList.clear(); + _whereList.clear(); + } + + /** + * Extract an image link from the point description + * @param inDesc description tag contents + * @return image link if found or null + */ + private static String getImgLink(String inDesc) + { + if (inDesc == null || inDesc.equals("")) {return null;} + // Pull out ', spos + 10); + if (spos < 0 || epos < 0) return null; + String imgtag = inDesc.substring(spos + 4, epos); + // Find the src attribute from img tag + int quotepos = imgtag.toLowerCase().indexOf("src="); + if (quotepos < 0) return null; + // source may be quoted with single or double quotes + char quotechar = imgtag.charAt(quotepos + 4); + int equotepos = imgtag.indexOf(quotechar, quotepos + 7); + if (equotepos < 0) return null; + return imgtag.substring(quotepos + 5, equotepos); + } + + /** + * Construct the String array for the given coordinates and name + * @param inCoordinates coordinate string in Kml format + * @param inName name of waypoint, or null if track point + * @param inDesc description of waypoint, if any + * @param inDesc timestamp of waypoint, if any + * @return String array for point + */ + private static String[] makeStringArray(String inCoordinates, + String inName, String inDesc, String inTimestamp) + { + String[] result = new String[7]; + String[] values = inCoordinates.split(","); + final int numValues = values.length; + if (numValues == 3 || numValues == 2) { + System.arraycopy(values, 0, result, 0, numValues); + } + result[3] = inName; + result[4] = inDesc; + result[6] = inTimestamp; + return result; + } + + + /** + * @see tim.prune.load.xml.XmlHandler#getFieldArray() + */ + public Field[] getFieldArray() + { + final Field[] fields = {Field.LONGITUDE, Field.LATITUDE, Field.ALTITUDE, + Field.WAYPT_NAME, Field.DESCRIPTION, Field.NEW_SEGMENT, Field.TIMESTAMP}; + return fields; + } + + + /** + * Return the parsed information as a 2d array + * @see tim.prune.load.xml.XmlHandler#getDataArray() + */ + public String[][] getDataArray() + { + int numPoints = _pointList.size(); + // construct data array + String[][] result = new String[numPoints][]; + for (int i=0; i