001/*
002 * Copyright 2006 - 2013
003 *     Stefan Balev     <stefan.balev@graphstream-project.org>
004 *     Julien Baudry    <julien.baudry@graphstream-project.org>
005 *     Antoine Dutot    <antoine.dutot@graphstream-project.org>
006 *     Yoann Pigné      <yoann.pigne@graphstream-project.org>
007 *     Guilhelm Savin   <guilhelm.savin@graphstream-project.org>
008 * 
009 * This file is part of GraphStream <http://graphstream-project.org>.
010 * 
011 * GraphStream is a library whose purpose is to handle static or dynamic
012 * graph, create them from scratch, file or any source and display them.
013 * 
014 * This program is free software distributed under the terms of two licenses, the
015 * CeCILL-C license that fits European law, and the GNU Lesser General Public
016 * License. You can  use, modify and/ or redistribute the software under the terms
017 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
018 * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by
019 * the Free Software Foundation, either version 3 of the License, or (at your
020 * option) any later version.
021 * 
022 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
023 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
024 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
025 * 
026 * You should have received a copy of the GNU Lesser General Public License
027 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
028 * 
029 * The fact that you are presently reading this means that you have had
030 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms.
031 */
032package org.graphstream.stream.file;
033
034import java.io.IOException;
035import java.util.EnumMap;
036import java.util.HashMap;
037import java.util.LinkedList;
038import java.util.List;
039
040import javax.xml.stream.XMLStreamException;
041import javax.xml.stream.events.XMLEvent;
042
043/**
044 * Source to read GPX (GPS eXchange Format) data an XML extension to exchange
045 * gps coordinates, routes and tracks.
046 * 
047 * Read more about GPX at <a
048 * href="https://en.wikipedia.org/wiki/GPS_eXchange_Format">Wikipedia</a>
049 * 
050 */
051public class FileSourceGPX extends FileSourceXML {
052
053        /**
054         * Parser used by this source.
055         */
056        protected GPXParser parser;
057
058        /**
059         * Flag to set strict mode.
060         */
061        protected boolean strict;
062
063        public FileSourceGPX() {
064                strict = false;
065        }
066
067        public void setStrict(boolean on) {
068                strict = on;
069        }
070        
071        public boolean isStrict() {
072                return strict;
073        }
074        
075        /*
076         * (non-Javadoc)
077         * 
078         * @see org.graphstream.stream.file.FileSourceXML#afterStartDocument()
079         */
080        protected void afterStartDocument() throws IOException, XMLStreamException {
081                parser = new GPXParser();
082                parser.__gpx();
083        }
084
085        /*
086         * (non-Javadoc)
087         * 
088         * @see org.graphstream.stream.file.FileSourceXML#beforeEndDocument()
089         */
090        protected void beforeEndDocument() throws IOException, XMLStreamException {
091                parser = null;
092        }
093
094        /*
095         * (non-Javadoc)
096         * 
097         * @see org.graphstream.stream.file.FileSourceXML#nextEvents()
098         */
099        public boolean nextEvents() throws IOException {
100                return false;
101        }
102
103        protected class WayPoint {
104                String name;
105                double lat, lon, ele;
106                HashMap<String, Object> attributes;
107
108                WayPoint() {
109                        attributes = new HashMap<String, Object>();
110                        name = null;
111                        lat = lon = ele = 0;
112                }
113
114                void deploy() {
115                        sendNodeAdded(sourceId, name);
116                        sendNodeAttributeAdded(sourceId, name, "xyz", new double[] { lon,
117                                        lat, ele });
118
119                        for (String key : attributes.keySet())
120                                sendNodeAttributeAdded(sourceId, name, key, attributes.get(key));
121                }
122        }
123
124        protected class GPXParser extends Parser implements GPXConstants {
125
126                int automaticPointId;
127                int automaticRouteId;
128                int automaticEdgeId;
129
130                GPXParser() {
131                        automaticRouteId = 0;
132                        automaticPointId = 0;
133                        automaticEdgeId = 0;
134                }
135
136                /**
137                 * Base for read points since points can be one of "wpt", "rtept",
138                 * "trkpt".
139                 * 
140                 * @param elementName
141                 * @return
142                 * @throws IOException
143                 * @throws XMLStreamException
144                 */
145                private WayPoint waypoint(String elementName) throws IOException,
146                                XMLStreamException {
147                        XMLEvent e;
148                        WayPoint wp = new WayPoint();
149                        EnumMap<WPTAttribute, String> attributes;
150                        LinkedList<String> links = new LinkedList<String>();
151
152                        e = getNextEvent();
153                        checkValid(e, XMLEvent.START_ELEMENT, elementName);
154
155                        attributes = getAttributes(WPTAttribute.class, e.asStartElement());
156
157                        if (!attributes.containsKey(WPTAttribute.LAT)) {
158                                XMLStreamException ex = newParseError(e,
159                                                "attribute 'lat' is required");
160
161                                if (strict)
162                                        throw ex;
163                                else
164                                        ex.printStackTrace();
165                        }
166
167                        if (!attributes.containsKey(WPTAttribute.LON)) {
168                                XMLStreamException ex = newParseError(e,
169                                                "attribute 'lon' is required");
170
171                                if (strict)
172                                        throw ex;
173                                else
174                                        ex.printStackTrace();
175                        }
176
177                        wp.lat = Double.parseDouble(attributes.get(WPTAttribute.LAT));
178                        wp.lon = Double.parseDouble(attributes.get(WPTAttribute.LON));
179                        wp.ele = 0;
180
181                        wp.attributes.put("lat", wp.lat);
182                        wp.attributes.put("lon", wp.lon);
183
184                        e = getNextEvent();
185
186                        if (isEvent(e, XMLEvent.START_ELEMENT, "ele")) {
187                                pushback(e);
188                                wp.ele = __ele();
189                                wp.attributes.put("ele", wp.ele);
190
191                                e = getNextEvent();
192                        }
193
194                        if (isEvent(e, XMLEvent.START_ELEMENT, "time")) {
195                                pushback(e);
196                                wp.attributes.put("time", __time());
197
198                                e = getNextEvent();
199                        }
200
201                        if (isEvent(e, XMLEvent.START_ELEMENT, "magvar")) {
202                                pushback(e);
203                                wp.attributes.put("magvar", __magvar());
204
205                                e = getNextEvent();
206                        }
207
208                        if (isEvent(e, XMLEvent.START_ELEMENT, "geoidheight")) {
209                                pushback(e);
210                                wp.attributes.put("geoidheight", __geoidheight());
211
212                                e = getNextEvent();
213                        }
214
215                        if (isEvent(e, XMLEvent.START_ELEMENT, "name")) {
216                                pushback(e);
217                                wp.name = __name();
218
219                                e = getNextEvent();
220                        }
221
222                        if (isEvent(e, XMLEvent.START_ELEMENT, "cmt")) {
223                                pushback(e);
224                                wp.attributes.put("cmt", __cmt());
225
226                                e = getNextEvent();
227                        }
228
229                        if (isEvent(e, XMLEvent.START_ELEMENT, "desc")) {
230                                pushback(e);
231                                wp.attributes.put("desc", __desc());
232
233                                e = getNextEvent();
234                        }
235
236                        if (isEvent(e, XMLEvent.START_ELEMENT, "src")) {
237                                pushback(e);
238                                wp.attributes.put("src", __src());
239
240                                e = getNextEvent();
241                        }
242
243                        while (isEvent(e, XMLEvent.START_ELEMENT, "link")) {
244                                pushback(e);
245                                links.add(__link());
246
247                                e = getNextEvent();
248                        }
249
250                        wp.attributes.put("link", links.toArray(new String[links.size()]));
251
252                        if (isEvent(e, XMLEvent.START_ELEMENT, "sym")) {
253                                pushback(e);
254                                wp.attributes.put("sym", __sym());
255
256                                e = getNextEvent();
257                        }
258
259                        if (isEvent(e, XMLEvent.START_ELEMENT, "type")) {
260                                pushback(e);
261                                wp.attributes.put("type", __type());
262
263                                e = getNextEvent();
264                        }
265
266                        if (isEvent(e, XMLEvent.START_ELEMENT, "fix")) {
267                                pushback(e);
268                                wp.attributes.put("fix", __fix());
269
270                                e = getNextEvent();
271                        }
272
273                        if (isEvent(e, XMLEvent.START_ELEMENT, "sat")) {
274                                pushback(e);
275                                wp.attributes.put("sat", __sat());
276
277                                e = getNextEvent();
278                        }
279
280                        if (isEvent(e, XMLEvent.START_ELEMENT, "hdop")) {
281                                pushback(e);
282                                wp.attributes.put("hdop", __hdop());
283
284                                e = getNextEvent();
285                        }
286
287                        if (isEvent(e, XMLEvent.START_ELEMENT, "vdop")) {
288                                pushback(e);
289                                wp.attributes.put("vdop", __vdop());
290
291                                e = getNextEvent();
292                        }
293
294                        if (isEvent(e, XMLEvent.START_ELEMENT, "pdop")) {
295                                pushback(e);
296                                wp.attributes.put("pdop", __pdop());
297
298                                e = getNextEvent();
299                        }
300
301                        if (isEvent(e, XMLEvent.START_ELEMENT, "ageofdgpsdata")) {
302                                pushback(e);
303                                wp.attributes.put("ageofdgpsdata", __ageofdgpsdata());
304
305                                e = getNextEvent();
306                        }
307
308                        if (isEvent(e, XMLEvent.START_ELEMENT, "dgpsid")) {
309                                pushback(e);
310                                wp.attributes.put("dgpsid", __dgpsid());
311
312                                e = getNextEvent();
313                        }
314
315                        if (isEvent(e, XMLEvent.START_ELEMENT, "extensions")) {
316                                pushback(e);
317                                __extensions();
318
319                                e = getNextEvent();
320                        }
321
322                        checkValid(e, XMLEvent.END_ELEMENT, elementName);
323
324                        if (wp.name == null)
325                                wp.name = String.format("wp#%08x", automaticPointId++);
326
327                        return wp;
328                }
329
330                /**
331                 * <pre>
332                 * name       : GPX
333                 * attributes : GPXAttribute
334                 * structure  : METADATA? WPT* RTE* TRK* EXTENSIONS?
335                 * </pre>
336                 * 
337                 * @throws IOException
338                 * @throws XMLStreamException
339                 */
340                private void __gpx() throws IOException, XMLStreamException {
341                        XMLEvent e;
342                        EnumMap<GPXAttribute, String> attributes;
343
344                        e = getNextEvent();
345                        checkValid(e, XMLEvent.START_ELEMENT, "gpx");
346
347                        attributes = getAttributes(GPXAttribute.class, e.asStartElement());
348
349                        if (!attributes.containsKey(GPXAttribute.VERSION)) {
350                                XMLStreamException ex = newParseError(e,
351                                                "attribute 'version' is required");
352
353                                if (strict)
354                                        throw ex;
355                                else
356                                        ex.printStackTrace();
357                        } else {
358                                sendGraphAttributeAdded(sourceId, "gpx.version", attributes
359                                                .get(GPXAttribute.VERSION));
360                        }
361
362                        if (!attributes.containsKey(GPXAttribute.CREATOR)) {
363                                XMLStreamException ex = newParseError(e,
364                                                "attribute 'creator' is required");
365
366                                if (strict)
367                                        throw ex;
368                                else
369                                        ex.printStackTrace();
370                        } else {
371                                sendGraphAttributeAdded(sourceId, "gpx.creator", attributes
372                                                .get(GPXAttribute.CREATOR));
373                        }
374
375                        e = getNextEvent();
376
377                        if (isEvent(e, XMLEvent.START_ELEMENT, "metadata")) {
378                                pushback(e);
379                                __metadata();
380
381                                e = getNextEvent();
382                        }
383
384                        while (isEvent(e, XMLEvent.START_ELEMENT, "wpt")) {
385                                pushback(e);
386                                __wpt();
387
388                                e = getNextEvent();
389                        }
390
391                        while (isEvent(e, XMLEvent.START_ELEMENT, "rte")) {
392                                pushback(e);
393                                __rte();
394
395                                e = getNextEvent();
396                        }
397
398                        while (isEvent(e, XMLEvent.START_ELEMENT, "trk")) {
399                                pushback(e);
400                                __trk();
401
402                                e = getNextEvent();
403                        }
404
405                        if (isEvent(e, XMLEvent.START_ELEMENT, "extensions")) {
406                                pushback(e);
407                                __extensions();
408
409                                e = getNextEvent();
410                        }
411
412                        checkValid(e, XMLEvent.END_ELEMENT, "gpx");
413                }
414
415                /**
416                 * <pre>
417                 * name       : METADATA
418                 * attributes : 
419                 * structure  : NAME? DESC? AUTHOR? COPYRIGHT? LINK* TIME? KEYWORDS? BOUNDS? EXTENSIONS?
420                 * </pre>
421                 * 
422                 * @throws IOException
423                 * @throws XMLStreamException
424                 */
425                private void __metadata() throws IOException, XMLStreamException {
426                        XMLEvent e;
427
428                        e = getNextEvent();
429                        checkValid(e, XMLEvent.START_ELEMENT, "metadata");
430
431                        e = getNextEvent();
432
433                        if (isEvent(e, XMLEvent.START_ELEMENT, "name")) {
434                                pushback(e);
435                                sendGraphAttributeAdded(sourceId, "gpx.metadata.name", __name());
436
437                                e = getNextEvent();
438                        }
439
440                        if (isEvent(e, XMLEvent.START_ELEMENT, "desc")) {
441                                pushback(e);
442                                sendGraphAttributeAdded(sourceId, "gpx.metadata.desc", __desc());
443
444                                e = getNextEvent();
445                        }
446
447                        if (isEvent(e, XMLEvent.START_ELEMENT, "author")) {
448                                pushback(e);
449                                sendGraphAttributeAdded(sourceId, "gpx.metadata.author",
450                                                __author());
451
452                                e = getNextEvent();
453                        }
454
455                        if (isEvent(e, XMLEvent.START_ELEMENT, "copyright")) {
456                                pushback(e);
457                                sendGraphAttributeAdded(sourceId, "gpx.metadata.copyright",
458                                                __copyright());
459
460                                e = getNextEvent();
461                        }
462
463                        LinkedList<String> links = new LinkedList<String>();
464
465                        while (isEvent(e, XMLEvent.START_ELEMENT, "link")) {
466                                pushback(e);
467                                links.add(__link());
468
469                                e = getNextEvent();
470                        }
471
472                        if (links.size() > 0)
473                                sendGraphAttributeAdded(sourceId, "gpx.metadata.links", links
474                                                .toArray(new String[links.size()]));
475
476                        if (isEvent(e, XMLEvent.START_ELEMENT, "time")) {
477                                pushback(e);
478                                sendGraphAttributeAdded(sourceId, "gpx.metadata.time", __time());
479
480                                e = getNextEvent();
481                        }
482
483                        if (isEvent(e, XMLEvent.START_ELEMENT, "keywords")) {
484                                pushback(e);
485                                sendGraphAttributeAdded(sourceId, "gpx.metadata.keywords",
486                                                __keywords());
487
488                                e = getNextEvent();
489                        }
490
491                        if (isEvent(e, XMLEvent.START_ELEMENT, "bounds")) {
492                                pushback(e);
493                                __bounds();
494
495                                e = getNextEvent();
496                        }
497
498                        if (isEvent(e, XMLEvent.START_ELEMENT, "extensions")) {
499                                pushback(e);
500                                __extensions();
501
502                                e = getNextEvent();
503                        }
504
505                        checkValid(e, XMLEvent.END_ELEMENT, "metadata");
506                }
507
508                /**
509                 * <pre>
510                 * name       : WPT
511                 * attributes : WPTAttribute
512                 * structure  : ELE? TIME? MAGVAR? GEOIDHEIGHT? NAME? CMT? DESC? SRC? LINK* SYM? TYPE? FIX? SAT? HDOP? VDOP? PDOP? AGEOFDGPSDATA? DGPSID? EXTENSIONS?
513                 * </pre>
514                 * 
515                 * @throws IOException
516                 * @throws XMLStreamException
517                 */
518                private void __wpt() throws IOException, XMLStreamException {
519                        WayPoint wp = waypoint("wpt");
520                        wp.deploy();
521                }
522
523                /**
524                 * <pre>
525                 * name       : RTE
526                 * attributes : 
527                 * structure  : NAME? CMT? DESC? SRC? LINK* NUMBER? TYPE? EXTENSIONS? RTEPT*
528                 * </pre>
529                 * 
530                 * @throws IOException
531                 * @throws XMLStreamException
532                 */
533                private void __rte() throws IOException, XMLStreamException {
534                        XMLEvent e;
535                        String name, cmt, desc, src, type, time;
536                        int number;
537                        LinkedList<String> links = new LinkedList<String>();
538                        LinkedList<WayPoint> points = new LinkedList<WayPoint>();
539
540                        name = cmt = desc = src = type = time = null;
541                        number = -1;
542
543                        e = getNextEvent();
544                        checkValid(e, XMLEvent.START_ELEMENT, "rte");
545
546                        e = getNextEvent();
547
548                        if (isEvent(e, XMLEvent.START_ELEMENT, "name")) {
549                                pushback(e);
550                                name = __name();
551
552                                e = getNextEvent();
553                        }
554
555                        if (isEvent(e, XMLEvent.START_ELEMENT, "time")) {
556                                pushback(e);
557                                time = __time();
558
559                                e = getNextEvent();
560                        }
561
562                        if (isEvent(e, XMLEvent.START_ELEMENT, "cmt")) {
563                                pushback(e);
564                                cmt = __cmt();
565
566                                e = getNextEvent();
567                        }
568
569                        if (isEvent(e, XMLEvent.START_ELEMENT, "desc")) {
570                                pushback(e);
571                                desc = __desc();
572
573                                e = getNextEvent();
574                        }
575
576                        if (isEvent(e, XMLEvent.START_ELEMENT, "src")) {
577                                pushback(e);
578                                src = __src();
579
580                                e = getNextEvent();
581                        }
582
583                        while (isEvent(e, XMLEvent.START_ELEMENT, "link")) {
584                                pushback(e);
585                                links.add(__link());
586
587                                e = getNextEvent();
588                        }
589
590                        if (isEvent(e, XMLEvent.START_ELEMENT, "number")) {
591                                pushback(e);
592                                number = __number();
593
594                                e = getNextEvent();
595                        }
596
597                        if (isEvent(e, XMLEvent.START_ELEMENT, "type")) {
598                                pushback(e);
599                                type = __type();
600
601                                e = getNextEvent();
602                        }
603
604                        if (isEvent(e, XMLEvent.START_ELEMENT, "extensions")) {
605                                pushback(e);
606                                __extensions();
607
608                                e = getNextEvent();
609                        }
610
611                        while (isEvent(e, XMLEvent.START_ELEMENT, "rtept")) {
612                                pushback(e);
613                                points.addLast(__rtept());
614
615                                e = getNextEvent();
616                        }
617
618                        checkValid(e, XMLEvent.END_ELEMENT, "rte");
619
620                        if (name == null)
621                                name = String.format("route#%08x", automaticRouteId++);
622
623                        sendGraphAttributeAdded(sourceId, "routes." + name, Boolean.TRUE);
624                        sendGraphAttributeAdded(sourceId, "routes." + name + ".desc", desc);
625                        sendGraphAttributeAdded(sourceId, "routes." + name + ".cmt", cmt);
626                        sendGraphAttributeAdded(sourceId, "routes." + name + ".src", src);
627                        sendGraphAttributeAdded(sourceId, "routes." + name + ".type", type);
628                        sendGraphAttributeAdded(sourceId, "routes." + name + ".time", time);
629                        sendGraphAttributeAdded(sourceId, "routes." + name + ".number",
630                                        number);
631
632                        for (int i = 0; i < points.size(); i++) {
633                                points.get(i).deploy();
634
635                                if (i > 0) {
636                                        String eid = String.format("seg#%08x", automaticEdgeId++);
637                                        sendEdgeAdded(sourceId, eid, points.get(i - 1).name, points
638                                                        .get(i).name, true);
639                                        sendEdgeAttributeAdded(sourceId, eid, "route", name);
640                                }
641                        }
642                }
643
644                /**
645                 * <pre>
646                 * name       : TRK
647                 * attributes : 
648                 * structure  : NAME? CMT? DESC? SRC? LINK* NUMBER? TYPE? EXTENSIONS? TRKSEG*
649                 * </pre>
650                 * 
651                 * @throws IOException
652                 * @throws XMLStreamException
653                 */
654                private void __trk() throws IOException, XMLStreamException {
655                        XMLEvent e;
656                        String name, cmt, desc, src, type, time;
657                        int number;
658                        LinkedList<String> links = new LinkedList<String>();
659
660                        name = cmt = desc = src = type = time = null;
661                        number = -1;
662
663                        e = getNextEvent();
664                        checkValid(e, XMLEvent.START_ELEMENT, "trk");
665
666                        e = getNextEvent();
667
668                        if (isEvent(e, XMLEvent.START_ELEMENT, "name")) {
669                                pushback(e);
670                                name = __name();
671
672                                e = getNextEvent();
673                        }
674
675                        if (isEvent(e, XMLEvent.START_ELEMENT, "time")) {
676                                pushback(e);
677                                time = __time();
678
679                                e = getNextEvent();
680                        }
681
682                        if (isEvent(e, XMLEvent.START_ELEMENT, "cmt")) {
683                                pushback(e);
684                                cmt = __cmt();
685
686                                e = getNextEvent();
687                        }
688
689                        if (isEvent(e, XMLEvent.START_ELEMENT, "desc")) {
690                                pushback(e);
691                                desc = __desc();
692
693                                e = getNextEvent();
694                        }
695
696                        if (isEvent(e, XMLEvent.START_ELEMENT, "src")) {
697                                pushback(e);
698                                src = __src();
699
700                                e = getNextEvent();
701                        }
702
703                        while (isEvent(e, XMLEvent.START_ELEMENT, "link")) {
704                                pushback(e);
705                                links.add(__link());
706
707                                e = getNextEvent();
708                        }
709
710                        if (isEvent(e, XMLEvent.START_ELEMENT, "number")) {
711                                pushback(e);
712                                number = __number();
713
714                                e = getNextEvent();
715                        }
716
717                        if (isEvent(e, XMLEvent.START_ELEMENT, "type")) {
718                                pushback(e);
719                                type = __type();
720
721                                e = getNextEvent();
722                        }
723
724                        if (isEvent(e, XMLEvent.START_ELEMENT, "extensions")) {
725                                pushback(e);
726                                __extensions();
727
728                                e = getNextEvent();
729                        }
730
731                        if (name == null)
732                                name = String.format("route#%08x", automaticRouteId++);
733
734                        sendGraphAttributeAdded(sourceId, "tracks." + name, Boolean.TRUE);
735                        sendGraphAttributeAdded(sourceId, "tracks." + name + ".desc", desc);
736                        sendGraphAttributeAdded(sourceId, "tracks." + name + ".cmt", cmt);
737                        sendGraphAttributeAdded(sourceId, "tracks." + name + ".src", src);
738                        sendGraphAttributeAdded(sourceId, "tracks." + name + ".type", type);
739                        sendGraphAttributeAdded(sourceId, "tracks." + name + ".time", time);
740                        sendGraphAttributeAdded(sourceId, "tracks." + name + ".number",
741                                        number);
742
743                        while (isEvent(e, XMLEvent.START_ELEMENT, "trkseg")) {
744                                pushback(e);
745                                List<WayPoint> wps = __trkseg();
746
747                                for (int i = 0; i < wps.size(); i++) {
748                                        wps.get(i).deploy();
749
750                                        if (i > 0) {
751                                                String eid = String.format("seg#%08x",
752                                                                automaticEdgeId++);
753                                                sendEdgeAdded(sourceId, eid, wps.get(i - 1).name, wps
754                                                                .get(i).name, true);
755                                                sendEdgeAttributeAdded(sourceId, eid, "route", name);
756                                        }
757                                }
758
759                                e = getNextEvent();
760                        }
761
762                        checkValid(e, XMLEvent.END_ELEMENT, "trk");
763                }
764
765                /**
766                 * <pre>
767                 * name       : EXTENSIONS
768                 * attributes : 
769                 * structure  :
770                 * </pre>
771                 * 
772                 * @throws IOException
773                 * @throws XMLStreamException
774                 */
775                private void __extensions() throws IOException, XMLStreamException {
776                        XMLEvent e;
777                        int stack = 0;
778
779                        e = getNextEvent();
780                        checkValid(e, XMLEvent.START_ELEMENT, "extensions");
781
782                        e = getNextEvent();
783
784                        while (!(isEvent(e, XMLEvent.END_ELEMENT, "extensions") && stack == 0)) {
785                                if (isEvent(e, XMLEvent.END_ELEMENT, "extensions"))
786                                        stack--;
787                                else if (isEvent(e, XMLEvent.START_ELEMENT, "extensions"))
788                                        stack++;
789
790                                e = getNextEvent();
791                        }
792                }
793
794                /**
795                 * <pre>
796                 * name       : NAME
797                 * attributes : 
798                 * structure  : string
799                 * </pre>
800                 * 
801                 * @throws IOException
802                 * @throws XMLStreamException
803                 */
804                private String __name() throws IOException, XMLStreamException {
805                        String name;
806                        XMLEvent e;
807
808                        e = getNextEvent();
809                        checkValid(e, XMLEvent.START_ELEMENT, "name");
810
811                        name = __characters();
812
813                        e = getNextEvent();
814                        checkValid(e, XMLEvent.END_ELEMENT, "name");
815
816                        return name;
817                }
818
819                /**
820                 * <pre>
821                 * name       : DESC
822                 * attributes : 
823                 * structure  : string
824                 * </pre>
825                 * 
826                 * @throws IOException
827                 * @throws XMLStreamException
828                 */
829                private String __desc() throws IOException, XMLStreamException {
830                        String desc;
831                        XMLEvent e;
832
833                        e = getNextEvent();
834                        checkValid(e, XMLEvent.START_ELEMENT, "desc");
835
836                        desc = __characters();
837
838                        e = getNextEvent();
839                        checkValid(e, XMLEvent.END_ELEMENT, "desc");
840
841                        return desc;
842                }
843
844                /**
845                 * <pre>
846                 * name       : AUTHOR
847                 * attributes : 
848                 * structure  : NAME? EMAIL? LINK?
849                 * </pre>
850                 * 
851                 * @throws IOException
852                 * @throws XMLStreamException
853                 */
854                private String __author() throws IOException, XMLStreamException {
855                        String author = "";
856                        XMLEvent e;
857
858                        e = getNextEvent();
859                        checkValid(e, XMLEvent.START_ELEMENT, "author");
860
861                        e = getNextEvent();
862
863                        if (isEvent(e, XMLEvent.START_ELEMENT, "name")) {
864                                pushback(e);
865                                author += __name();
866
867                                e = getNextEvent();
868                        }
869
870                        if (isEvent(e, XMLEvent.START_ELEMENT, "email")) {
871                                pushback(e);
872                                author += " <" + __email() + ">";
873
874                                e = getNextEvent();
875                        }
876
877                        if (isEvent(e, XMLEvent.START_ELEMENT, "link")) {
878                                pushback(e);
879                                author += " (" + __link() + ")";
880
881                                e = getNextEvent();
882                        }
883
884                        e = getNextEvent();
885                        checkValid(e, XMLEvent.END_ELEMENT, "author");
886
887                        return author;
888                }
889
890                /**
891                 * <pre>
892                 * name       : COPYRIGHT
893                 * attributes : COPYRIGHTAttribute
894                 * structure  : YEAR? LICENCE?
895                 * </pre>
896                 * 
897                 * @throws IOException
898                 * @throws XMLStreamException
899                 */
900                private String __copyright() throws IOException, XMLStreamException {
901                        String copyright;
902                        XMLEvent e;
903                        EnumMap<COPYRIGHTAttribute, String> attributes;
904
905                        e = getNextEvent();
906                        checkValid(e, XMLEvent.START_ELEMENT, "copyright");
907
908                        attributes = getAttributes(COPYRIGHTAttribute.class, e
909                                        .asStartElement());
910
911                        if (!attributes.containsKey(COPYRIGHTAttribute.AUTHOR)) {
912                                XMLStreamException ex = newParseError(e,
913                                                "attribute 'author' is required");
914
915                                if (strict)
916                                        throw ex;
917                                else
918                                        ex.printStackTrace();
919
920                                copyright = "unknown";
921                        } else
922                                copyright = attributes.get(COPYRIGHTAttribute.AUTHOR);
923
924                        e = getNextEvent();
925
926                        if (isEvent(e, XMLEvent.START_ELEMENT, "year")) {
927                                pushback(e);
928                                copyright += " " + __year();
929
930                                e = getNextEvent();
931                        }
932
933                        if (isEvent(e, XMLEvent.START_ELEMENT, "license")) {
934                                pushback(e);
935                                copyright += " " + __license();
936
937                                e = getNextEvent();
938                        }
939
940                        checkValid(e, XMLEvent.END_ELEMENT, "copyright");
941
942                        return copyright;
943                }
944
945                /**
946                 * <pre>
947                 * name       : LINK
948                 * attributes : LINKAttribute
949                 * structure  : TEXT? TYPE?
950                 * </pre>
951                 * 
952                 * @throws IOException
953                 * @throws XMLStreamException
954                 */
955                private String __link() throws IOException, XMLStreamException {
956                        String link;
957                        XMLEvent e;
958                        EnumMap<LINKAttribute, String> attributes;
959
960                        e = getNextEvent();
961                        checkValid(e, XMLEvent.START_ELEMENT, "link");
962
963                        attributes = getAttributes(LINKAttribute.class, e.asStartElement());
964
965                        if (!attributes.containsKey(LINKAttribute.HREF)) {
966                                XMLStreamException ex = newParseError(e,
967                                                "attribute 'href' is required");
968
969                                if (strict)
970                                        throw ex;
971                                else
972                                        ex.printStackTrace();
973
974                                link = "unknown";
975                        } else
976                                link = attributes.get(LINKAttribute.HREF);
977
978                        e = getNextEvent();
979
980                        if (isEvent(e, XMLEvent.START_ELEMENT, "text")) {
981                                pushback(e);
982                                __text();
983
984                                e = getNextEvent();
985                        }
986
987                        if (isEvent(e, XMLEvent.START_ELEMENT, "type")) {
988                                pushback(e);
989                                __type();
990
991                                e = getNextEvent();
992                        }
993
994                        checkValid(e, XMLEvent.END_ELEMENT, "link");
995
996                        return link;
997                }
998
999                /**
1000                 * <pre>
1001                 * name       : TIME
1002                 * attributes : 
1003                 * structure  : string
1004                 * </pre>
1005                 * 
1006                 * @throws IOException
1007                 * @throws XMLStreamException
1008                 */
1009                private String __time() throws IOException, XMLStreamException {
1010                        String time;
1011                        XMLEvent e;
1012
1013                        e = getNextEvent();
1014                        checkValid(e, XMLEvent.START_ELEMENT, "time");
1015
1016                        time = __characters();
1017
1018                        e = getNextEvent();
1019                        checkValid(e, XMLEvent.END_ELEMENT, "time");
1020
1021                        return time;
1022                }
1023
1024                /**
1025                 * <pre>
1026                 * name       : KEYWORDS
1027                 * attributes : 
1028                 * structure  : string
1029                 * </pre>
1030                 * 
1031                 * @throws IOException
1032                 * @throws XMLStreamException
1033                 */
1034                private String __keywords() throws IOException, XMLStreamException {
1035                        String keywords;
1036                        XMLEvent e;
1037
1038                        e = getNextEvent();
1039                        checkValid(e, XMLEvent.START_ELEMENT, "keywords");
1040
1041                        keywords = __characters();
1042
1043                        e = getNextEvent();
1044                        checkValid(e, XMLEvent.END_ELEMENT, "keywords");
1045
1046                        return keywords;
1047                }
1048
1049                /**
1050                 * <pre>
1051                 * name       : BOUNDS
1052                 * attributes : BOUNDSAttribute
1053                 * structure  :
1054                 * </pre>
1055                 * 
1056                 * @throws IOException
1057                 * @throws XMLStreamException
1058                 */
1059                private void __bounds() throws IOException, XMLStreamException {
1060                        XMLEvent e;
1061                        EnumMap<BOUNDSAttribute, String> attributes;
1062                        double minlat, maxlat, minlon, maxlon;
1063
1064                        e = getNextEvent();
1065                        checkValid(e, XMLEvent.START_ELEMENT, "bounds");
1066
1067                        attributes = getAttributes(BOUNDSAttribute.class, e
1068                                        .asStartElement());
1069
1070                        if (!attributes.containsKey(BOUNDSAttribute.MINLAT)) {
1071                                XMLStreamException ex = newParseError(e,
1072                                                "attribute 'minlat' is required");
1073
1074                                if (strict)
1075                                        throw ex;
1076                                else
1077                                        ex.printStackTrace();
1078                        }
1079
1080                        if (!attributes.containsKey(BOUNDSAttribute.MAXLAT)) {
1081                                XMLStreamException ex = newParseError(e,
1082                                                "attribute 'maxlat' is required");
1083
1084                                if (strict)
1085                                        throw ex;
1086                                else
1087                                        ex.printStackTrace();
1088                        }
1089
1090                        if (!attributes.containsKey(BOUNDSAttribute.MINLON)) {
1091                                XMLStreamException ex = newParseError(e,
1092                                                "attribute 'minlon' is required");
1093
1094                                if (strict)
1095                                        throw ex;
1096                                else
1097                                        ex.printStackTrace();
1098                        }
1099
1100                        if (!attributes.containsKey(BOUNDSAttribute.MAXLON)) {
1101                                XMLStreamException ex = newParseError(e,
1102                                                "attribute 'maxlon' is required");
1103
1104                                if (strict)
1105                                        throw ex;
1106                                else
1107                                        ex.printStackTrace();
1108                        }
1109
1110                        minlat = Double.parseDouble(attributes.get(BOUNDSAttribute.MINLAT));
1111                        maxlat = Double.parseDouble(attributes.get(BOUNDSAttribute.MAXLAT));
1112                        minlon = Double.parseDouble(attributes.get(BOUNDSAttribute.MINLON));
1113                        maxlon = Double.parseDouble(attributes.get(BOUNDSAttribute.MAXLON));
1114
1115                        sendGraphAttributeAdded(sourceId, "gpx.bounds", new double[] {
1116                                        minlat, minlon, maxlat, maxlon });
1117
1118                        e = getNextEvent();
1119                        checkValid(e, XMLEvent.END_ELEMENT, "bounds");
1120                }
1121
1122                /**
1123                 * <pre>
1124                 * name       : ELE
1125                 * attributes : 
1126                 * structure  : double
1127                 * </pre>
1128                 * 
1129                 * @throws IOException
1130                 * @throws XMLStreamException
1131                 */
1132                private double __ele() throws IOException, XMLStreamException {
1133                        String ele;
1134                        XMLEvent e;
1135
1136                        e = getNextEvent();
1137                        checkValid(e, XMLEvent.START_ELEMENT, "ele");
1138
1139                        ele = __characters();
1140
1141                        e = getNextEvent();
1142                        checkValid(e, XMLEvent.END_ELEMENT, "ele");
1143
1144                        return Double.parseDouble(ele);
1145                }
1146
1147                /**
1148                 * <pre>
1149                 * name       : MAGVAR
1150                 * attributes : 
1151                 * structure  : double in [0,360]
1152                 * </pre>
1153                 * 
1154                 * @throws IOException
1155                 * @throws XMLStreamException
1156                 */
1157                private double __magvar() throws IOException, XMLStreamException {
1158                        String magvar;
1159                        XMLEvent e;
1160
1161                        e = getNextEvent();
1162                        checkValid(e, XMLEvent.START_ELEMENT, "magvar");
1163
1164                        magvar = __characters();
1165
1166                        e = getNextEvent();
1167                        checkValid(e, XMLEvent.END_ELEMENT, "magvar");
1168
1169                        return Double.parseDouble(magvar);
1170                }
1171
1172                /**
1173                 * <pre>
1174                 * name       : GEOIDHEIGHT
1175                 * attributes : 
1176                 * structure  : double
1177                 * </pre>
1178                 * 
1179                 * @throws IOException
1180                 * @throws XMLStreamException
1181                 */
1182                private double __geoidheight() throws IOException, XMLStreamException {
1183                        String geoidheight;
1184                        XMLEvent e;
1185
1186                        e = getNextEvent();
1187                        checkValid(e, XMLEvent.START_ELEMENT, "geoidheight");
1188
1189                        geoidheight = __characters();
1190
1191                        e = getNextEvent();
1192                        checkValid(e, XMLEvent.END_ELEMENT, "geoidheight");
1193
1194                        return Double.parseDouble(geoidheight);
1195                }
1196
1197                /**
1198                 * <pre>
1199                 * name       : CMT
1200                 * attributes : 
1201                 * structure  : string
1202                 * </pre>
1203                 * 
1204                 * @throws IOException
1205                 * @throws XMLStreamException
1206                 */
1207                private String __cmt() throws IOException, XMLStreamException {
1208                        String cmt;
1209                        XMLEvent e;
1210
1211                        e = getNextEvent();
1212                        checkValid(e, XMLEvent.START_ELEMENT, "cmt");
1213
1214                        cmt = __characters();
1215
1216                        e = getNextEvent();
1217                        checkValid(e, XMLEvent.END_ELEMENT, "cmt");
1218
1219                        return cmt;
1220                }
1221
1222                /**
1223                 * <pre>
1224                 * name       : SRC
1225                 * attributes : 
1226                 * structure  : string
1227                 * </pre>
1228                 * 
1229                 * @throws IOException
1230                 * @throws XMLStreamException
1231                 */
1232                private String __src() throws IOException, XMLStreamException {
1233                        String src;
1234                        XMLEvent e;
1235
1236                        e = getNextEvent();
1237                        checkValid(e, XMLEvent.START_ELEMENT, "src");
1238
1239                        src = __characters();
1240
1241                        e = getNextEvent();
1242                        checkValid(e, XMLEvent.END_ELEMENT, "src");
1243
1244                        return src;
1245                }
1246
1247                /**
1248                 * <pre>
1249                 * name       : SYM
1250                 * attributes : 
1251                 * structure  : string
1252                 * </pre>
1253                 * 
1254                 * @throws IOException
1255                 * @throws XMLStreamException
1256                 */
1257                private String __sym() throws IOException, XMLStreamException {
1258                        String sym;
1259                        XMLEvent e;
1260
1261                        e = getNextEvent();
1262                        checkValid(e, XMLEvent.START_ELEMENT, "sym");
1263
1264                        sym = __characters();
1265
1266                        e = getNextEvent();
1267                        checkValid(e, XMLEvent.END_ELEMENT, "sym");
1268
1269                        return sym;
1270                }
1271
1272                /**
1273                 * <pre>
1274                 * name       : TEXT
1275                 * attributes : 
1276                 * structure  : string
1277                 * </pre>
1278                 * 
1279                 * @throws IOException
1280                 * @throws XMLStreamException
1281                 */
1282                private String __text() throws IOException, XMLStreamException {
1283                        String text;
1284                        XMLEvent e;
1285
1286                        e = getNextEvent();
1287                        checkValid(e, XMLEvent.START_ELEMENT, "text");
1288
1289                        text = __characters();
1290
1291                        e = getNextEvent();
1292                        checkValid(e, XMLEvent.END_ELEMENT, "text");
1293
1294                        return text;
1295                }
1296
1297                /**
1298                 * <pre>
1299                 * name       : TYPE
1300                 * attributes : 
1301                 * structure  : string
1302                 * </pre>
1303                 * 
1304                 * @throws IOException
1305                 * @throws XMLStreamException
1306                 */
1307                private String __type() throws IOException, XMLStreamException {
1308                        String type;
1309                        XMLEvent e;
1310
1311                        e = getNextEvent();
1312                        checkValid(e, XMLEvent.START_ELEMENT, "type");
1313
1314                        type = __characters();
1315
1316                        e = getNextEvent();
1317                        checkValid(e, XMLEvent.END_ELEMENT, "type");
1318
1319                        return type;
1320                }
1321
1322                /**
1323                 * <pre>
1324                 * name       : FIX
1325                 * attributes : 
1326                 * structure  : enum FixType
1327                 * </pre>
1328                 * 
1329                 * @throws IOException
1330                 * @throws XMLStreamException
1331                 */
1332                private String __fix() throws IOException, XMLStreamException {
1333                        String fix;
1334                        XMLEvent e;
1335
1336                        e = getNextEvent();
1337                        checkValid(e, XMLEvent.START_ELEMENT, "fix");
1338
1339                        fix = __characters();
1340
1341                        if (!fix.toLowerCase().matches("^(none|2d|3d|dgps|pps)$"))
1342                                throw newParseError(e,
1343                                                "invalid fix type, expecting one of 'none', '2d', '3d', 'dgps', 'pps'");
1344
1345                        e = getNextEvent();
1346                        checkValid(e, XMLEvent.END_ELEMENT, "fix");
1347
1348                        return fix;
1349                }
1350
1351                /**
1352                 * <pre>
1353                 * name       : SAT
1354                 * attributes : 
1355                 * structure  : positive integer
1356                 * </pre>
1357                 * 
1358                 * @throws IOException
1359                 * @throws XMLStreamException
1360                 */
1361                private int __sat() throws IOException, XMLStreamException {
1362                        String sat;
1363                        XMLEvent e;
1364
1365                        e = getNextEvent();
1366                        checkValid(e, XMLEvent.START_ELEMENT, "sat");
1367
1368                        sat = __characters();
1369
1370                        e = getNextEvent();
1371                        checkValid(e, XMLEvent.END_ELEMENT, "sat");
1372
1373                        return Integer.parseInt(sat);
1374                }
1375
1376                /**
1377                 * <pre>
1378                 * name       : HDOP
1379                 * attributes : 
1380                 * structure  : double
1381                 * </pre>
1382                 * 
1383                 * @throws IOException
1384                 * @throws XMLStreamException
1385                 */
1386                private double __hdop() throws IOException, XMLStreamException {
1387                        String hdop;
1388                        XMLEvent e;
1389
1390                        e = getNextEvent();
1391                        checkValid(e, XMLEvent.START_ELEMENT, "hdop");
1392
1393                        hdop = __characters();
1394
1395                        e = getNextEvent();
1396                        checkValid(e, XMLEvent.END_ELEMENT, "hdop");
1397
1398                        return Double.parseDouble(hdop);
1399                }
1400
1401                /**
1402                 * <pre>
1403                 * name       : VDOP
1404                 * attributes : 
1405                 * structure  : double
1406                 * </pre>
1407                 * 
1408                 * @throws IOException
1409                 * @throws XMLStreamException
1410                 */
1411                private double __vdop() throws IOException, XMLStreamException {
1412                        String vdop;
1413                        XMLEvent e;
1414
1415                        e = getNextEvent();
1416                        checkValid(e, XMLEvent.START_ELEMENT, "vdop");
1417
1418                        vdop = __characters();
1419
1420                        e = getNextEvent();
1421                        checkValid(e, XMLEvent.END_ELEMENT, "vdop");
1422
1423                        return Double.parseDouble(vdop);
1424                }
1425
1426                /**
1427                 * <pre>
1428                 * name       : PDOP
1429                 * attributes : 
1430                 * structure  : double
1431                 * </pre>
1432                 * 
1433                 * @throws IOException
1434                 * @throws XMLStreamException
1435                 */
1436                private double __pdop() throws IOException, XMLStreamException {
1437                        String pdop;
1438                        XMLEvent e;
1439
1440                        e = getNextEvent();
1441                        checkValid(e, XMLEvent.START_ELEMENT, "pdop");
1442
1443                        pdop = __characters();
1444
1445                        e = getNextEvent();
1446                        checkValid(e, XMLEvent.END_ELEMENT, "pdop");
1447
1448                        return Double.parseDouble(pdop);
1449                }
1450
1451                /**
1452                 * <pre>
1453                 * name       : AGEOFDGPSDATA
1454                 * attributes : 
1455                 * structure  : double
1456                 * </pre>
1457                 * 
1458                 * @throws IOException
1459                 * @throws XMLStreamException
1460                 */
1461                private double __ageofdgpsdata() throws IOException, XMLStreamException {
1462                        String ageofdgpsdata;
1463                        XMLEvent e;
1464
1465                        e = getNextEvent();
1466                        checkValid(e, XMLEvent.START_ELEMENT, "ageofdgpsdata");
1467
1468                        ageofdgpsdata = __characters();
1469
1470                        e = getNextEvent();
1471                        checkValid(e, XMLEvent.END_ELEMENT, "ageofdgpsdata");
1472
1473                        return Double.parseDouble(ageofdgpsdata);
1474                }
1475
1476                /**
1477                 * <pre>
1478                 * name       : DGPSID
1479                 * attributes : 
1480                 * structure  : integer in [0,1023]
1481                 * </pre>
1482                 * 
1483                 * @throws IOException
1484                 * @throws XMLStreamException
1485                 */
1486                private int __dgpsid() throws IOException, XMLStreamException {
1487                        String dgpsid;
1488                        XMLEvent e;
1489
1490                        e = getNextEvent();
1491                        checkValid(e, XMLEvent.START_ELEMENT, "dgpsid");
1492
1493                        dgpsid = __characters();
1494
1495                        e = getNextEvent();
1496                        checkValid(e, XMLEvent.END_ELEMENT, "dgpsid");
1497
1498                        return Integer.parseInt(dgpsid);
1499                }
1500
1501                /**
1502                 * <pre>
1503                 * name       : NUMBER
1504                 * attributes : 
1505                 * structure  : positive integer
1506                 * </pre>
1507                 * 
1508                 * @throws IOException
1509                 * @throws XMLStreamException
1510                 */
1511                private int __number() throws IOException, XMLStreamException {
1512                        String number;
1513                        XMLEvent e;
1514
1515                        e = getNextEvent();
1516                        checkValid(e, XMLEvent.START_ELEMENT, "number");
1517
1518                        number = __characters();
1519
1520                        e = getNextEvent();
1521                        checkValid(e, XMLEvent.END_ELEMENT, "number");
1522
1523                        return Integer.parseInt(number);
1524                }
1525
1526                /**
1527                 * <pre>
1528                 * name       : RTEPT
1529                 * attributes : 
1530                 * structure  : __wptType
1531                 * </pre>
1532                 * 
1533                 * @throws IOException
1534                 * @throws XMLStreamException
1535                 */
1536                private WayPoint __rtept() throws IOException, XMLStreamException {
1537                        return waypoint("rtept");
1538                }
1539
1540                /**
1541                 * <pre>
1542                 * name       : TRKPT
1543                 * attributes : 
1544                 * structure  : __wptType
1545                 * </pre>
1546                 * 
1547                 * @throws IOException
1548                 * @throws XMLStreamException
1549                 */
1550                private WayPoint __trkpt() throws IOException, XMLStreamException {
1551                        return waypoint("trkpt");
1552                }
1553
1554                /**
1555                 * <pre>
1556                 * name       : TRKSEG
1557                 * attributes : 
1558                 * structure  : TRKPT* EXTENSIONS?
1559                 * </pre>
1560                 * 
1561                 * @throws IOException
1562                 * @throws XMLStreamException
1563                 */
1564                private List<WayPoint> __trkseg() throws IOException,
1565                                XMLStreamException {
1566                        LinkedList<WayPoint> points = new LinkedList<WayPoint>();
1567                        XMLEvent e;
1568
1569                        e = getNextEvent();
1570                        checkValid(e, XMLEvent.START_ELEMENT, "trkseg");
1571
1572                        e = getNextEvent();
1573
1574                        while (isEvent(e, XMLEvent.START_ELEMENT, "trkpt")) {
1575                                pushback(e);
1576                                points.addLast(__trkpt());
1577
1578                                e = getNextEvent();
1579                        }
1580
1581                        if (isEvent(e, XMLEvent.START_ELEMENT, "extensions")) {
1582                                pushback(e);
1583                                __extensions();
1584
1585                                e = getNextEvent();
1586                        }
1587
1588                        checkValid(e, XMLEvent.END_ELEMENT, "trkseg");
1589
1590                        return points;
1591                }
1592
1593                /**
1594                 * <pre>
1595                 * name       : EMAIL
1596                 * attributes : EMAILAttribute
1597                 * structure  :
1598                 * </pre>
1599                 * 
1600                 * @throws IOException
1601                 * @throws XMLStreamException
1602                 */
1603                private String __email() throws IOException, XMLStreamException {
1604                        XMLEvent e;
1605                        EnumMap<EMAILAttribute, String> attributes;
1606                        String email = "";
1607
1608                        e = getNextEvent();
1609                        checkValid(e, XMLEvent.START_ELEMENT, "email");
1610
1611                        attributes = getAttributes(EMAILAttribute.class, e.asStartElement());
1612
1613                        if (!attributes.containsKey(EMAILAttribute.ID)) {
1614                                XMLStreamException ex = newParseError(e,
1615                                                "attribute 'version' is required");
1616
1617                                if (strict)
1618                                        throw ex;
1619                                else
1620                                        ex.printStackTrace();
1621                        } else
1622                                email += attributes.get(EMAILAttribute.ID);
1623
1624                        email += "@";
1625
1626                        if (!attributes.containsKey(EMAILAttribute.DOMAIN)) {
1627                                XMLStreamException ex = newParseError(e,
1628                                                "attribute 'version' is required");
1629
1630                                if (strict)
1631                                        throw ex;
1632                                else
1633                                        ex.printStackTrace();
1634                        } else
1635                                email += attributes.get(EMAILAttribute.DOMAIN);
1636
1637                        e = getNextEvent();
1638                        checkValid(e, XMLEvent.END_ELEMENT, "email");
1639
1640                        return email;
1641                }
1642
1643                /**
1644                 * <pre>
1645                 * name       : YEAR
1646                 * attributes : 
1647                 * structure  : string
1648                 * </pre>
1649                 * 
1650                 * @throws IOException
1651                 * @throws XMLStreamException
1652                 */
1653                private String __year() throws IOException, XMLStreamException {
1654                        String year;
1655                        XMLEvent e;
1656
1657                        e = getNextEvent();
1658                        checkValid(e, XMLEvent.START_ELEMENT, "year");
1659
1660                        year = __characters();
1661
1662                        e = getNextEvent();
1663                        checkValid(e, XMLEvent.END_ELEMENT, "year");
1664
1665                        return year;
1666                }
1667
1668                /**
1669                 * <pre>
1670                 * name       : LICENSE
1671                 * attributes : 
1672                 * structure  : string
1673                 * </pre>
1674                 * 
1675                 * @throws IOException
1676                 * @throws XMLStreamException
1677                 */
1678                private String __license() throws IOException, XMLStreamException {
1679                        String license;
1680                        XMLEvent e;
1681
1682                        e = getNextEvent();
1683                        checkValid(e, XMLEvent.START_ELEMENT, "license");
1684
1685                        license = __characters();
1686
1687                        e = getNextEvent();
1688                        checkValid(e, XMLEvent.END_ELEMENT, "license");
1689
1690                        return license;
1691                }
1692        }
1693
1694        public static interface GPXConstants {
1695                public static enum Balise {
1696                        GPX, METADATA, WPT, RTE, TRK, EXTENSIONS, NAME, DESC, AUTHOR, COPYRIGHT, LINK, TIME, KEYWORDS, BOUNDS, ELE, MAGVAR, GEOIDHEIGHT, CMT, SRC, SYM, TYPE, FIX, SAT, HDOP, VDOP, PDOP, AGEOFDGPSDATA, DGPSID, NUMBER, RTEPT, TRKSEG, TRKPT, YEAR, LICENCE, TEXT, EMAIL, PT
1697                }
1698
1699                public static enum GPXAttribute {
1700                        CREATOR, VERSION
1701                }
1702
1703                public static enum WPTAttribute {
1704                        LAT, LON
1705                }
1706
1707                public static enum LINKAttribute {
1708                        HREF
1709                }
1710
1711                public static enum EMAILAttribute {
1712                        ID, DOMAIN
1713                }
1714
1715                public static enum PTAttribute {
1716                        LAT, LON
1717                }
1718
1719                public static enum BOUNDSAttribute {
1720                        MINLAT, MAXLAT, MINLON, MAXLON
1721                }
1722
1723                public static enum COPYRIGHTAttribute {
1724                        AUTHOR
1725                }
1726
1727                public static enum FixType {
1728                        T_NONE, T_2D, T_3D, T_DGPS, T_PPS
1729                }
1730        }
1731}