]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/load/xml/KmlHandler.java
Version 13.4, May 2012
[GpsPrune.git] / tim / prune / load / xml / KmlHandler.java
1 package tim.prune.load.xml;
2
3 import java.util.ArrayList;
4 import org.xml.sax.Attributes;
5 import org.xml.sax.SAXException;
6
7 import tim.prune.data.Field;
8
9
10 /**
11  * Class for handling specifics of parsing Kml files
12  */
13 public class KmlHandler extends XmlHandler
14 {
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>();
26
27
28         /**
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)
31          */
32         public void startElement(String uri, String localName, String qName,
33                 Attributes attributes) throws SAXException
34         {
35                 String tagName = localName;
36                 if (tagName == null || tagName.equals("")) {tagName = qName;}
37                 if (tagName.equalsIgnoreCase("Placemark")) {
38                         _coordinateList = new ArrayList<String>();
39                 }
40                 else if (tagName.equalsIgnoreCase("coordinates")) {
41                         _insideCoordinates = true;
42                         _coordinates = null;
43                 }
44                 _value = null;
45                 super.startElement(uri, localName, qName, attributes);
46         }
47
48
49         /**
50          * Process end tag
51          * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
52          */
53         public void endElement(String uri, String localName, String qName)
54         throws SAXException
55         {
56                 String tagName = localName;
57                 if (tagName == null || tagName.equals("")) {tagName = qName;}
58                 if (tagName.equalsIgnoreCase("Placemark"))
59                 {
60                         processPlacemark();
61                         _name = _desc = _imgLink = null;
62                 }
63                 else if (tagName.equalsIgnoreCase("coordinates")) {
64                         _insideCoordinates = false;
65                         if (_coordinates != null) _coordinateList.add(_coordinates.toString().trim());
66                 }
67                 else if (tagName.equalsIgnoreCase("name")) _name = _value;
68                 else if (tagName.equalsIgnoreCase("description")) {
69                         _desc = _value;
70                         _imgLink = getImgLink(_desc);
71                 }
72                 else if (tagName.equalsIgnoreCase("when")) {
73                         _whenList.add(_value);
74                 }
75                 else if (tagName.equalsIgnoreCase("gx:coord")) {
76                         _whereList.add(_value);
77                 }
78                 else if (tagName.equalsIgnoreCase("gx:Track")) {
79                         processGxTrack();
80                 }
81                 super.endElement(uri, localName, qName);
82         }
83
84
85         /**
86          * Process character text (inside tags or between them)
87          * @see org.xml.sax.ContentHandler#characters(char[], int, int)
88          */
89         public void characters(char[] ch, int start, int length)
90                         throws SAXException
91         {
92                 String val = new String(ch, start, length);
93                 if (_insideCoordinates)
94                 {
95                         if (_coordinates == null) {
96                                 _coordinates = new StringBuffer();
97                         }
98                         _coordinates.append(val);
99                 }
100                 else
101                 {
102                         // Store string in _value
103                         if (_value == null) _value = val;
104                         else _value = _value + val;
105                 }
106                 super.characters(ch, start, length);
107         }
108
109
110         /**
111          * Process a placemark entry, either a single waypoint or a whole track
112          */
113         private void processPlacemark()
114         {
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)
119                 {
120                         String[] coordArray = coords.split("[ \n]");
121                         int numPoints = coordArray.length;
122                         if (numPoints == 1)
123                         {
124                                 // Add single point to list
125                                 final String name = (isSingleSelection ? _name : null);
126                                 _pointList.add(makeStringArray(coords, name, _desc));
127                                 _linkList.add(_imgLink);
128                         }
129                         else if (numPoints > 1)
130                         {
131                                 // Add each of the unnamed track points to list
132                                 boolean firstPoint = true;
133                                 for (int p=0; p<numPoints; p++)
134                                 {
135                                         if (coordArray[p] != null && coordArray[p].trim().length()>3)
136                                         {
137                                                 String[] pointArray = makeStringArray(coordArray[p], null, null);
138                                                 if (firstPoint) {pointArray[5] = "1";} // start of segment flag
139                                                 firstPoint = false;
140                                                 _pointList.add(pointArray);
141                                         }
142                                         _linkList.add(null);
143                                 }
144                         }
145                 }
146         }
147
148         /**
149          * Process a Gx track including timestamps
150          */
151         private void processGxTrack()
152         {
153                 if (_whenList.size() > 0 && _whenList.size() == _whereList.size())
154                 {
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++)
159                         {
160                                 String when  = _whenList.get(p);
161                                 String where = _whereList.get(p);
162                                 if (where != null)
163                                 {
164                                         String[] coords = where.split(" ");
165                                         if (coords.length == 3)
166                                         {
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
173                                                 firstPoint = false;
174                                                 pointArray[6] = when; // timestamp
175                                                 _pointList.add(pointArray);
176                                         }
177                                 }
178                                 _linkList.add(null);
179                         }
180                 }
181                 _whenList.clear();
182                 _whereList.clear();
183         }
184
185         /**
186          * Extract an image link from the point description
187          * @param inDesc description tag contents
188          * @return image link if found or null
189          */
190         private static String getImgLink(String inDesc)
191         {
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);
206         }
207
208         /**
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
214          */
215         private static String[] makeStringArray(String inCoordinates,
216                 String inName, String inDesc)
217         {
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);
223                 }
224                 result[3] = inName;
225                 result[4] = inDesc;
226                 return result;
227         }
228
229
230         /**
231          * @see tim.prune.load.xml.XmlHandler#getFieldArray()
232          */
233         public Field[] getFieldArray()
234         {
235                 final Field[] fields = {Field.LONGITUDE, Field.LATITUDE, Field.ALTITUDE,
236                         Field.WAYPT_NAME, Field.DESCRIPTION, Field.NEW_SEGMENT, Field.TIMESTAMP};
237                 return fields;
238         }
239
240
241         /**
242          * Return the parsed information as a 2d array
243          * @see tim.prune.load.xml.XmlHandler#getDataArray()
244          */
245         public String[][] getDataArray()
246         {
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);
252                 }
253                 return result;
254         }
255
256         /**
257          * @return array of links, or null if none
258          */
259         public String[] getLinkArray()
260         {
261                 int numPoints = _linkList.size();
262                 boolean hasLink = false;
263                 String[] result = new String[numPoints];
264                 for (int i=0; i<numPoints; i++)
265                 {
266                         result[i] = _linkList.get(i);
267                         if (result[i] != null) {hasLink = true;}
268                 }
269                 if (!hasLink) {result = null;}
270                 return result;
271         }
272 }