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[]> _pointList = new ArrayList<String[]>();
21 private ArrayList<String> _linkList = new ArrayList<String>();
22 // variables for gx extensions
23 private ArrayList<String> _whenList = new ArrayList<String>();
24 private ArrayList<String> _whereList = new ArrayList<String>();
28 * Receive the start of a tag
29 * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
31 public void startElement(String uri, String localName, String qName,
32 Attributes attributes) throws SAXException
34 String tagName = localName;
35 if (tagName == null || tagName.equals("")) {tagName = qName;}
36 if (tagName.equalsIgnoreCase("coordinates")) {_insideCoordinates = true; _coordinates = null;}
38 super.startElement(uri, localName, qName, attributes);
44 * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
46 public void endElement(String uri, String localName, String qName)
49 String tagName = localName;
50 if (tagName == null || tagName.equals("")) {tagName = qName;}
51 if (tagName.equalsIgnoreCase("Placemark"))
54 _name = _desc = _imgLink = null;
56 else if (tagName.equalsIgnoreCase("coordinates")) _insideCoordinates = false;
57 else if (tagName.equalsIgnoreCase("name")) _name = _value;
58 else if (tagName.equalsIgnoreCase("description")) {
60 _imgLink = getImgLink(_desc);
62 else if (tagName.equalsIgnoreCase("when")) {
63 _whenList.add(_value);
65 else if (tagName.equalsIgnoreCase("gx:coord")) {
66 _whereList.add(_value);
68 else if (tagName.equalsIgnoreCase("gx:Track")) {
71 super.endElement(uri, localName, qName);
76 * Process character text (inside tags or between them)
77 * @see org.xml.sax.ContentHandler#characters(char[], int, int)
79 public void characters(char[] ch, int start, int length)
82 String val = new String(ch, start, length);
83 if (_insideCoordinates)
85 if (_coordinates == null) {
86 _coordinates = new StringBuffer();
88 _coordinates.append(val);
92 // Store string in _value
93 if (_value == null) _value = val;
94 else _value = _value + val;
96 super.characters(ch, start, length);
101 * Process a placemark entry, either a single waypoint or a whole track
103 private void processPlacemark()
105 if (_coordinates == null) return;
106 String allCoords = _coordinates.toString().trim();
107 String[] coordArray = allCoords.split("[ \n]");
108 int numPoints = coordArray.length;
111 // Add single waypoint to list
112 _pointList.add(makeStringArray(allCoords, _name, _desc));
113 _linkList.add(_imgLink);
115 else if (numPoints > 1)
117 // Add each of the unnamed track points to list
118 boolean firstPoint = true;
119 for (int p=0; p<numPoints; p++)
121 if (coordArray[p] != null && coordArray[p].trim().length()>3)
123 String[] pointArray = makeStringArray(coordArray[p], null, null);
124 if (firstPoint) {pointArray[5] = "1";} // start of segment flag
126 _pointList.add(pointArray);
134 * Process a Gx track including timestamps
136 private void processGxTrack()
138 if (_whenList.size() > 0 && _whenList.size() == _whereList.size())
140 // Add each of the unnamed track points to list
141 boolean firstPoint = true;
142 final int numPoints = _whenList.size();
143 for (int p=0; p < numPoints; p++)
145 String when = _whenList.get(p);
146 String where = _whereList.get(p);
149 String[] coords = where.split(" ");
150 if (coords.length == 3)
152 String[] pointArray = new String[7];
153 pointArray[0] = coords[0];
154 pointArray[1] = coords[1];
155 pointArray[2] = coords[2];
156 // leave name and description empty
157 if (firstPoint) {pointArray[5] = "1";} // start of segment flag
159 pointArray[6] = when; // timestamp
160 _pointList.add(pointArray);
171 * Extract an image link from the point description
172 * @param inDesc description tag contents
173 * @return image link if found or null
175 private static String getImgLink(String inDesc)
177 if (inDesc == null || inDesc.equals("")) {return null;}
178 // Pull out <img tag from description (if any)
179 int spos = inDesc.indexOf("<img");
180 int epos = inDesc.indexOf('>', spos + 10);
181 if (spos < 0 || epos < 0) return null;
182 String imgtag = inDesc.substring(spos + 4, epos);
183 // Find the src attribute from img tag
184 int quotepos = imgtag.toLowerCase().indexOf("src=");
185 if (quotepos < 0) return null;
186 // source may be quoted with single or double quotes
187 char quotechar = imgtag.charAt(quotepos + 4);
188 int equotepos = imgtag.indexOf(quotechar, quotepos + 7);
189 if (equotepos < 0) return null;
190 return imgtag.substring(quotepos + 5, equotepos);
194 * Construct the String array for the given coordinates and name
195 * @param inCoordinates coordinate string in Kml format
196 * @param inName name of waypoint, or null if track point
197 * @param inDesc description of waypoint, if any
198 * @return String array for point
200 private static String[] makeStringArray(String inCoordinates,
201 String inName, String inDesc)
203 String[] result = new String[7];
204 String[] values = inCoordinates.split(",");
205 final int numValues = values.length;
206 if (numValues == 3 || numValues == 2) {
207 System.arraycopy(values, 0, result, 0, numValues);
216 * @see tim.prune.load.xml.XmlHandler#getFieldArray()
218 public Field[] getFieldArray()
220 final Field[] fields = {Field.LONGITUDE, Field.LATITUDE, Field.ALTITUDE,
221 Field.WAYPT_NAME, Field.DESCRIPTION, Field.NEW_SEGMENT, Field.TIMESTAMP};
227 * Return the parsed information as a 2d array
228 * @see tim.prune.load.xml.XmlHandler#getDataArray()
230 public String[][] getDataArray()
232 int numPoints = _pointList.size();
233 // construct data array
234 String[][] result = new String[numPoints][];
235 for (int i=0; i<numPoints; i++) {
236 result[i] = _pointList.get(i);
242 * @return array of links, or null if none
244 public String[] getLinkArray()
246 int numPoints = _linkList.size();
247 boolean hasLink = false;
248 String[] result = new String[numPoints];
249 for (int i=0; i<numPoints; i++)
251 result[i] = _linkList.get(i);
252 if (result[i] != null) {hasLink = true;}
254 if (!hasLink) {result = null;}