]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/load/xml/KmlHandler.java
Version 13, August 2011
[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[]> _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>();
25
26
27         /**
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)
30          */
31         public void startElement(String uri, String localName, String qName,
32                 Attributes attributes) throws SAXException
33         {
34                 String tagName = localName;
35                 if (tagName == null || tagName.equals("")) {tagName = qName;}
36                 if (tagName.equalsIgnoreCase("coordinates")) {_insideCoordinates = true; _coordinates = null;}
37                 _value = null;
38                 super.startElement(uri, localName, qName, attributes);
39         }
40
41
42         /**
43          * Process end tag
44          * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
45          */
46         public void endElement(String uri, String localName, String qName)
47         throws SAXException
48         {
49                 String tagName = localName;
50                 if (tagName == null || tagName.equals("")) {tagName = qName;}
51                 if (tagName.equalsIgnoreCase("Placemark"))
52                 {
53                         processPlacemark();
54                         _name = _desc = _imgLink = null;
55                 }
56                 else if (tagName.equalsIgnoreCase("coordinates")) _insideCoordinates = false;
57                 else if (tagName.equalsIgnoreCase("name")) _name = _value;
58                 else if (tagName.equalsIgnoreCase("description")) {
59                         _desc = _value;
60                         _imgLink = getImgLink(_desc);
61                 }
62                 else if (tagName.equalsIgnoreCase("when")) {
63                         _whenList.add(_value);
64                 }
65                 else if (tagName.equalsIgnoreCase("gx:coord")) {
66                         _whereList.add(_value);
67                 }
68                 else if (tagName.equalsIgnoreCase("gx:Track")) {
69                         processGxTrack();
70                 }
71                 super.endElement(uri, localName, qName);
72         }
73
74
75         /**
76          * Process character text (inside tags or between them)
77          * @see org.xml.sax.ContentHandler#characters(char[], int, int)
78          */
79         public void characters(char[] ch, int start, int length)
80                         throws SAXException
81         {
82                 String val = new String(ch, start, length);
83                 if (_insideCoordinates)
84                 {
85                         if (_coordinates == null) {
86                                 _coordinates = new StringBuffer();
87                         }
88                         _coordinates.append(val);
89                 }
90                 else
91                 {
92                         // Store string in _value
93                         if (_value == null) _value = val;
94                         else _value = _value + val;
95                 }
96                 super.characters(ch, start, length);
97         }
98
99
100         /**
101          * Process a placemark entry, either a single waypoint or a whole track
102          */
103         private void processPlacemark()
104         {
105                 if (_coordinates == null) return;
106                 String allCoords = _coordinates.toString().trim();
107                 String[] coordArray = allCoords.split("[ \n]");
108                 int numPoints = coordArray.length;
109                 if (numPoints == 1)
110                 {
111                         // Add single waypoint to list
112                         _pointList.add(makeStringArray(allCoords, _name, _desc));
113                         _linkList.add(_imgLink);
114                 }
115                 else if (numPoints > 1)
116                 {
117                         // Add each of the unnamed track points to list
118                         boolean firstPoint = true;
119                         for (int p=0; p<numPoints; p++)
120                         {
121                                 if (coordArray[p] != null && coordArray[p].trim().length()>3)
122                                 {
123                                         String[] pointArray = makeStringArray(coordArray[p], null, null);
124                                         if (firstPoint) {pointArray[5] = "1";} // start of segment flag
125                                         firstPoint = false;
126                                         _pointList.add(pointArray);
127                                 }
128                                 _linkList.add(null);
129                         }
130                 }
131         }
132
133         /**
134          * Process a Gx track including timestamps
135          */
136         private void processGxTrack()
137         {
138                 if (_whenList.size() > 0 && _whenList.size() == _whereList.size())
139                 {
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++)
144                         {
145                                 String when  = _whenList.get(p);
146                                 String where = _whereList.get(p);
147                                 if (where != null)
148                                 {
149                                         String[] coords = where.split(" ");
150                                         if (coords.length == 3)
151                                         {
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
158                                                 firstPoint = false;
159                                                 pointArray[6] = when; // timestamp
160                                                 _pointList.add(pointArray);
161                                         }
162                                 }
163                                 _linkList.add(null);
164                         }
165                 }
166                 _whenList.clear();
167                 _whereList.clear();
168         }
169
170         /**
171          * Extract an image link from the point description
172          * @param inDesc description tag contents
173          * @return image link if found or null
174          */
175         private static String getImgLink(String inDesc)
176         {
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);
191         }
192
193         /**
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
199          */
200         private static String[] makeStringArray(String inCoordinates,
201                 String inName, String inDesc)
202         {
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);
208                 }
209                 result[3] = inName;
210                 result[4] = inDesc;
211                 return result;
212         }
213
214
215         /**
216          * @see tim.prune.load.xml.XmlHandler#getFieldArray()
217          */
218         public Field[] getFieldArray()
219         {
220                 final Field[] fields = {Field.LONGITUDE, Field.LATITUDE, Field.ALTITUDE,
221                         Field.WAYPT_NAME, Field.DESCRIPTION, Field.NEW_SEGMENT, Field.TIMESTAMP};
222                 return fields;
223         }
224
225
226         /**
227          * Return the parsed information as a 2d array
228          * @see tim.prune.load.xml.XmlHandler#getDataArray()
229          */
230         public String[][] getDataArray()
231         {
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);
237                 }
238                 return result;
239         }
240
241         /**
242          * @return array of links, or null if none
243          */
244         public String[] getLinkArray()
245         {
246                 int numPoints = _linkList.size();
247                 boolean hasLink = false;
248                 String[] result = new String[numPoints];
249                 for (int i=0; i<numPoints; i++)
250                 {
251                         result[i] = _linkList.get(i);
252                         if (result[i] != null) {hasLink = true;}
253                 }
254                 if (!hasLink) {result = null;}
255                 return result;
256         }
257 }