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 String _value = null;
17 private String _name = null, _desc = null;
18 private String _imgLink = null;
19 private StringBuffer _coordinates = null;
20 private ArrayList<String> _coordinateList = null;
21 private ArrayList<String[]> _pointList = new ArrayList<String[]>();
22 private ArrayList<String> _linkList = new ArrayList<String>();
23 // variables for gx extensions
24 private ArrayList<String> _whenList = new ArrayList<String>();
25 private ArrayList<String> _whereList = new ArrayList<String>();
29 * Receive the start of a tag
30 * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
32 public void startElement(String uri, String localName, String qName,
33 Attributes attributes) throws SAXException
35 String tagName = localName;
36 if (tagName == null || tagName.equals("")) {tagName = qName;}
37 if (tagName.equalsIgnoreCase("Placemark")) {
38 _coordinateList = new ArrayList<String>();
40 else if (tagName.equalsIgnoreCase("coordinates")) {
41 _insideCoordinates = true;
45 super.startElement(uri, localName, qName, attributes);
51 * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
53 public void endElement(String uri, String localName, String qName)
56 String tagName = localName;
57 if (tagName == null || tagName.equals("")) {tagName = qName;}
58 if (tagName.equalsIgnoreCase("Placemark"))
61 _name = _desc = _imgLink = null;
63 else if (tagName.equalsIgnoreCase("coordinates")) {
64 _insideCoordinates = false;
65 if (_coordinates != null) _coordinateList.add(_coordinates.toString().trim());
67 else if (tagName.equalsIgnoreCase("name")) _name = _value;
68 else if (tagName.equalsIgnoreCase("description")) {
70 _imgLink = getImgLink(_desc);
72 else if (tagName.equalsIgnoreCase("when")) {
73 _whenList.add(_value);
75 else if (tagName.equalsIgnoreCase("gx:coord")) {
76 _whereList.add(_value);
78 else if (tagName.equalsIgnoreCase("gx:Track")) {
81 super.endElement(uri, localName, qName);
86 * Process character text (inside tags or between them)
87 * @see org.xml.sax.ContentHandler#characters(char[], int, int)
89 public void characters(char[] ch, int start, int length)
92 String val = new String(ch, start, length);
93 if (_insideCoordinates)
95 if (_coordinates == null) {
96 _coordinates = new StringBuffer();
98 _coordinates.append(val);
102 // Store string in _value
103 if (_value == null) _value = val;
104 else _value = _value + val;
106 super.characters(ch, start, length);
111 * Process a placemark entry, either a single waypoint or a whole track
113 private void processPlacemark()
115 if (_coordinateList == null || _coordinateList.isEmpty()) return;
116 final boolean isSingleSelection = (_coordinateList.size() == 1);
117 // Loop over coordinate sets in list (may have multiple <coordinates> tags within single placemark)
118 for (String coords : _coordinateList)
120 String[] coordArray = coords.split("[ \n]");
121 int numPoints = coordArray.length;
124 // Add single point to list
125 final String name = (isSingleSelection ? _name : null);
126 _pointList.add(makeStringArray(coords, name, _desc));
127 _linkList.add(_imgLink);
129 else if (numPoints > 1)
131 // Add each of the unnamed track points to list
132 boolean firstPoint = true;
133 for (int p=0; p<numPoints; p++)
135 if (coordArray[p] != null && coordArray[p].trim().length()>3)
137 String[] pointArray = makeStringArray(coordArray[p], null, null);
138 if (firstPoint) {pointArray[5] = "1";} // start of segment flag
140 _pointList.add(pointArray);
149 * Process a Gx track including timestamps
151 private void processGxTrack()
153 if (_whenList.size() > 0 && _whenList.size() == _whereList.size())
155 // Add each of the unnamed track points to list
156 boolean firstPoint = true;
157 final int numPoints = _whenList.size();
158 for (int p=0; p < numPoints; p++)
160 String when = _whenList.get(p);
161 String where = _whereList.get(p);
164 String[] coords = where.split(" ");
165 if (coords.length == 3)
167 String[] pointArray = new String[7];
168 pointArray[0] = coords[0];
169 pointArray[1] = coords[1];
170 pointArray[2] = coords[2];
171 // leave name and description empty
172 if (firstPoint) {pointArray[5] = "1";} // start of segment flag
174 pointArray[6] = when; // timestamp
175 _pointList.add(pointArray);
186 * Extract an image link from the point description
187 * @param inDesc description tag contents
188 * @return image link if found or null
190 private static String getImgLink(String inDesc)
192 if (inDesc == null || inDesc.equals("")) {return null;}
193 // Pull out <img tag from description (if any)
194 int spos = inDesc.indexOf("<img");
195 int epos = inDesc.indexOf('>', spos + 10);
196 if (spos < 0 || epos < 0) return null;
197 String imgtag = inDesc.substring(spos + 4, epos);
198 // Find the src attribute from img tag
199 int quotepos = imgtag.toLowerCase().indexOf("src=");
200 if (quotepos < 0) return null;
201 // source may be quoted with single or double quotes
202 char quotechar = imgtag.charAt(quotepos + 4);
203 int equotepos = imgtag.indexOf(quotechar, quotepos + 7);
204 if (equotepos < 0) return null;
205 return imgtag.substring(quotepos + 5, equotepos);
209 * Construct the String array for the given coordinates and name
210 * @param inCoordinates coordinate string in Kml format
211 * @param inName name of waypoint, or null if track point
212 * @param inDesc description of waypoint, if any
213 * @return String array for point
215 private static String[] makeStringArray(String inCoordinates,
216 String inName, String inDesc)
218 String[] result = new String[7];
219 String[] values = inCoordinates.split(",");
220 final int numValues = values.length;
221 if (numValues == 3 || numValues == 2) {
222 System.arraycopy(values, 0, result, 0, numValues);
231 * @see tim.prune.load.xml.XmlHandler#getFieldArray()
233 public Field[] getFieldArray()
235 final Field[] fields = {Field.LONGITUDE, Field.LATITUDE, Field.ALTITUDE,
236 Field.WAYPT_NAME, Field.DESCRIPTION, Field.NEW_SEGMENT, Field.TIMESTAMP};
242 * Return the parsed information as a 2d array
243 * @see tim.prune.load.xml.XmlHandler#getDataArray()
245 public String[][] getDataArray()
247 int numPoints = _pointList.size();
248 // construct data array
249 String[][] result = new String[numPoints][];
250 for (int i=0; i<numPoints; i++) {
251 result[i] = _pointList.get(i);
257 * @return array of links, or null if none
259 public String[] getLinkArray()
261 int numPoints = _linkList.size();
262 boolean hasLink = false;
263 String[] result = new String[numPoints];
264 for (int i=0; i<numPoints; i++)
266 result[i] = _linkList.get(i);
267 if (result[i] != null) {hasLink = true;}
269 if (!hasLink) {result = null;}