1 package tim.prune.load.xml;
3 import java.util.ArrayList;
4 import org.xml.sax.Attributes;
5 import org.xml.sax.SAXException;
7 import tim.prune.data.Field;
11 * Class for handling specifics of parsing Kml files
13 public class KmlHandler extends XmlHandler
15 private boolean _insideCoordinates = false;
16 private boolean _insideGxTrack = false;
17 private String _value = null;
18 private String _name = null, _desc = null;
19 private String _timestamp = null, _imgLink = null;
20 private StringBuffer _coordinates = null;
21 private ArrayList<String> _coordinateList = null;
22 private ArrayList<String[]> _pointList = new ArrayList<String[]>();
23 private ArrayList<String> _linkList = new ArrayList<String>();
24 // variables for gx extensions
25 private ArrayList<String> _whenList = new ArrayList<String>();
26 private ArrayList<String> _whereList = new ArrayList<String>();
30 * Receive the start of a tag
31 * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
33 public void startElement(String uri, String localName, String qName,
34 Attributes attributes) throws SAXException
36 String tagName = localName;
37 if (tagName == null || tagName.equals("")) {tagName = qName;}
38 tagName = tagName.toLowerCase();
40 if (tagName.equals("placemark"))
42 _coordinateList = new ArrayList<String>();
44 else if (tagName.equals("coordinates"))
46 _insideCoordinates = true;
49 else if (tagName.equals("gx:track"))
51 _insideGxTrack = true;
54 super.startElement(uri, localName, qName, attributes);
60 * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
62 public void endElement(String uri, String localName, String qName)
65 String tagName = localName;
66 if (tagName == null || tagName.equals("")) {tagName = qName;}
67 tagName = tagName.toLowerCase();
69 if (tagName.equals("placemark"))
72 _name = _desc = _imgLink = _timestamp = null;
74 else if (tagName.equals("coordinates"))
76 _insideCoordinates = false;
77 if (_coordinates != null) _coordinateList.add(_coordinates.toString().trim());
79 else if (tagName.equals("name"))
83 else if (tagName.equals("description"))
86 _imgLink = getImgLink(_desc);
88 else if (tagName.equals("when"))
93 _whenList.add(_value);
95 else if (tagName.equals("gx:coord"))
98 _whereList.add(_value);
101 else if (tagName.equals("gx:track"))
104 _insideGxTrack = false;
106 super.endElement(uri, localName, qName);
111 * Process character text (inside tags or between them)
112 * @see org.xml.sax.ContentHandler#characters(char[], int, int)
114 public void characters(char[] ch, int start, int length)
117 String val = new String(ch, start, length);
118 if (_insideCoordinates)
120 if (_coordinates == null) {
121 _coordinates = new StringBuffer();
123 _coordinates.append(val);
127 // Store string in _value
128 if (_value == null) _value = val;
129 else _value = _value + val;
131 super.characters(ch, start, length);
136 * Process a placemark entry, either a single waypoint or a whole track
138 private void processPlacemark()
140 if (_coordinateList == null || _coordinateList.isEmpty()) return;
141 final boolean isSingleSelection = (_coordinateList.size() == 1);
142 // Loop over coordinate sets in list (may have multiple <coordinates> tags within single placemark)
143 for (String coords : _coordinateList)
145 String[] coordArray = coords.split("[ \n]");
146 int numPoints = coordArray.length;
149 // Add single point to list
150 final String name = (isSingleSelection ? _name : null);
151 _pointList.add(makeStringArray(coords, name, _desc, _timestamp));
152 _linkList.add(_imgLink);
154 else if (numPoints > 1)
156 // Add each of the unnamed track points to list
157 boolean firstPoint = true;
158 for (int p=0; p<numPoints; p++)
160 if (coordArray[p] != null && coordArray[p].trim().length()>3)
162 String[] pointArray = makeStringArray(coordArray[p], null, null, null);
163 if (firstPoint) {pointArray[5] = "1";} // start of segment flag
165 _pointList.add(pointArray);
174 * Process a Gx track including timestamps
176 private void processGxTrack()
178 if (!_whereList.isEmpty())
180 // If the whens don't match, then throw them all away
181 if (_whenList.size() != _whereList.size()) {System.out.println("clearing!"); _whenList.clear();}
183 // Add each of the unnamed track points to list
184 boolean firstPoint = true;
185 final int numPoints = _whenList.size();
186 for (int p=0; p < numPoints; p++)
188 String when = (_whenList.isEmpty() ? null : _whenList.get(p));
189 String where = _whereList.get(p);
192 String[] coords = where.split(" ");
193 if (coords.length == 3)
195 String[] pointArray = new String[7];
196 pointArray[0] = coords[0];
197 pointArray[1] = coords[1];
198 pointArray[2] = coords[2];
199 // leave name and description empty
200 if (firstPoint) {pointArray[5] = "1";} // start of segment flag
202 pointArray[6] = when; // timestamp
203 _pointList.add(pointArray);
214 * Extract an image link from the point description
215 * @param inDesc description tag contents
216 * @return image link if found or null
218 private static String getImgLink(String inDesc)
220 if (inDesc == null || inDesc.equals("")) {return null;}
221 // Pull out <img tag from description (if any)
222 int spos = inDesc.indexOf("<img");
223 int epos = inDesc.indexOf('>', spos + 10);
224 if (spos < 0 || epos < 0) return null;
225 String imgtag = inDesc.substring(spos + 4, epos);
226 // Find the src attribute from img tag
227 int quotepos = imgtag.toLowerCase().indexOf("src=");
228 if (quotepos < 0) return null;
229 // source may be quoted with single or double quotes
230 char quotechar = imgtag.charAt(quotepos + 4);
231 int equotepos = imgtag.indexOf(quotechar, quotepos + 7);
232 if (equotepos < 0) return null;
233 return imgtag.substring(quotepos + 5, equotepos);
237 * Construct the String array for the given coordinates and name
238 * @param inCoordinates coordinate string in Kml format
239 * @param inName name of waypoint, or null if track point
240 * @param inDesc description of waypoint, if any
241 * @param inDesc timestamp of waypoint, if any
242 * @return String array for point
244 private static String[] makeStringArray(String inCoordinates,
245 String inName, String inDesc, String inTimestamp)
247 String[] result = new String[7];
248 String[] values = inCoordinates.split(",");
249 final int numValues = values.length;
250 if (numValues == 3 || numValues == 2) {
251 System.arraycopy(values, 0, result, 0, numValues);
255 result[6] = inTimestamp;
261 * @see tim.prune.load.xml.XmlHandler#getFieldArray()
263 public Field[] getFieldArray()
265 final Field[] fields = {Field.LONGITUDE, Field.LATITUDE, Field.ALTITUDE,
266 Field.WAYPT_NAME, Field.DESCRIPTION, Field.NEW_SEGMENT, Field.TIMESTAMP};
272 * Return the parsed information as a 2d array
273 * @see tim.prune.load.xml.XmlHandler#getDataArray()
275 public String[][] getDataArray()
277 int numPoints = _pointList.size();
278 // construct data array
279 String[][] result = new String[numPoints][];
280 for (int i=0; i<numPoints; i++) {
281 result[i] = _pointList.get(i);
287 * @return array of links, or null if none
289 public String[] getLinkArray()
291 int numPoints = _linkList.size();
292 boolean hasLink = false;
293 String[] result = new String[numPoints];
294 for (int i=0; i<numPoints; i++)
296 result[i] = _linkList.get(i);
297 if (result[i] != null) {hasLink = true;}
299 if (!hasLink) {result = null;}