Search code examples
javasax

Parsing dates with SAX Java


I am having trouble parsing dates of a gpx file with SAX. Somehow it fails to get the <time> tag of some nodes correctly. Most of the nodes are ok, and it doesn't seem have any problem with other tags.
I am testing on different gpx files and it always fails on the same nodes on the same files and there are no special characters or anything. And it is cyclical.

enter image description here

I am printing the node number next to the error. And the 3th column is the difference between the current error and the last error

enter image description here

It usually starts around the 800 to 1000 the first error. As you can see the dates are not being picked properly, for some reason they are trimmed.

This is my handler

package ec.com.mapachedev.webmapper.gpx;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class SAXFileHandler extends DefaultHandler {
    private String reading;
    private List<SAXTrack> tracks;
    private List<SAXWayPoint> waypoints;
    private List<SAXTrackPoint> trackpoints;
    private SAXTrack track;
    private SAXTrackPoint trackPoint;
    private SAXWayPoint wayPoint;
    private LocalDateTime fechaExtraido;
    private LocalDateTime fechaIni;
    private LocalDateTime fechaFin;
    private DateTimeFormatter parser = DateTimeFormatter
            .ofPattern("[yyyy-MM-dd'T'HH:mm:ss.SSS'Z']" + "[yyyy-MM-dd'T'HH:mm:ss'Z']");
    private boolean isWaypoint = false;
    private boolean isTrackPoint = false;
    private int cont = 0;

    public SAXFileHandler() {
        super();
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        try {
            if (qName.equals("trkpt")) {
                trackPoint = new SAXTrackPoint();
                isWaypoint = false;
                isTrackPoint = true;
                try {
                    trackPoint.setLat(Double.parseDouble(attributes.getValue("lat")));
                    trackPoint.setLon(Double.parseDouble(attributes.getValue("lon")));
                } catch (Exception e) {
                    System.out.println("Error " + e.getMessage());
                }

            } /*
                 * else if (qName.equals("trkseg")) {
                 * 
                 * }
                 */else if (qName.equals("trk")) {
                track = new SAXTrack();
                isWaypoint = false;
                isTrackPoint = false;
            } else if (qName.equals("wpt")) {
                isWaypoint = true;
                isTrackPoint = false;
                wayPoint = new SAXWayPoint();
                try {
                    wayPoint.setLat(Double.parseDouble(attributes.getValue("lat")));
                    wayPoint.setLon(Double.parseDouble(attributes.getValue("lon")));
                } catch (Exception e) {
                    System.out.println("Error " + e.getMessage());
                }
            } else if (qName.equals("gpx")) {
                tracks = new ArrayList<SAXTrack>();
                waypoints = new ArrayList<SAXWayPoint>();

                isWaypoint = false;
                isTrackPoint = false;
            }
        } finally {
            // no matter the node, we empty the StringBuilder accumulator when
            // we start
            // a new node.
            reading=null;
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {

        if (qName.equals("trkpt")) {
            track.getPuntos().add(trackPoint);
        } else if (qName.equals("speed")) {
            try {
                trackPoint.setVelocidad(Double.parseDouble(reading));
            } catch (Exception e) {
                System.out.println("Error " + e.getMessage());
            }
        } else if (qName.equals("time") && isTrackPoint) {
            System.out.println("Time Track " + reading + " "
                    + cont++);/*
                                 * try { cont++;
                                 * //System.out.println("Time Track " + reading
                                 * + " "+cont++);
                                 * trackPoint.setFecha(LocalDateTime.parse(
                                 * reading, parser)); // Siempre guardamos la
                                 * ultima fecha y si es la primer vez que //
                                 * grabamos fechas tambien ponemos fechaInicial
                                 * fechaFin = trackPoint.getFecha(); if
                                 * (fechaIni == null) fechaIni =
                                 * trackPoint.getFecha(); } catch (Exception e)
                                 * { System.out.println("Error " +
                                 * e.getMessage()+" " +cont); }
                                 */
        } else if (qName.equals("ele") && isTrackPoint) {
            try {
                trackPoint.setEle(Double.parseDouble(reading));
            } catch (Exception e) {
                System.out.println("Error " + e.getMessage());
            }
        } else if (qName.equals("name") && isTrackPoint) {
            // System.out.println("Nombre: "+reading);
            trackPoint.setNombre(reading);
        } else if (qName.equals("desc") && !isWaypoint && !isTrackPoint) {
            track.setDesc(reading);
        } else if (qName.equals("name") && !isWaypoint && !isTrackPoint) {
            track.setName(reading);
        } else if (qName.equals("desc") && isWaypoint) {
            wayPoint.setDesc(reading);
        } else if (qName.equals("cmt") && isWaypoint) {
            wayPoint.setCmt(reading);
        } else if (qName.equals("name") && isWaypoint) {
            wayPoint.setCmt(reading);
        } else if (qName.equals("time") && isWaypoint) {
            System.out.println("Time WP " + reading);
            wayPoint.setFecha(LocalDateTime.parse(reading, parser));
        } else if (qName.equals("ele") && isWaypoint) {
            try {
                wayPoint.setEle(Double.parseDouble(reading));
            } catch (Exception e) {
                System.out.println("Error " + e.getMessage());
            }
        } else if (qName.equals("trk")) {
            tracks.add(track);
        } else if (qName.equals("time") && tracks.size() == 0) {
            System.out.println("Time GPX " + reading);
            fechaExtraido = LocalDateTime.parse(reading, parser);
        }

    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        reading = new String(ch, start, length);
    }

    public List<SAXTrack> getTracks() {
        return tracks;
    }

    public void setTracks(List<SAXTrack> tracks) {
        this.tracks = tracks;
    }

    public List<SAXWayPoint> getWaypoints() {
        return waypoints;
    }

    public void setWaypoints(List<SAXWayPoint> waypoints) {
        this.waypoints = waypoints;
    }

    public List<SAXTrackPoint> getTrackpoints() {
        return trackpoints;
    }

    public void setTrackpoints(List<SAXTrackPoint> trackpoints) {
        this.trackpoints = trackpoints;
    }

    public SAXTrack getTrack() {
        return track;
    }

    public void setTrack(SAXTrack track) {
        this.track = track;
    }

    public SAXTrackPoint getTrackPoint() {
        return trackPoint;
    }

    public void setTrackPoint(SAXTrackPoint trackPoint) {
        this.trackPoint = trackPoint;
    }

    public SAXWayPoint getWayPoint() {
        return wayPoint;
    }

    public void setWayPoint(SAXWayPoint wayPoint) {
        this.wayPoint = wayPoint;
    }

    public LocalDateTime getFechaExtraido() {
        return fechaExtraido;
    }

    public void setFechaExtraido(LocalDateTime fechaExtraido) {
        this.fechaExtraido = fechaExtraido;
    }

    public LocalDateTime getFechaIni() {
        return fechaIni;
    }

    public void setFechaIni(LocalDateTime fechaIni) {
        this.fechaIni = fechaIni;
    }

    public LocalDateTime getFechaFin() {
        return fechaFin;
    }

    public void setFechaFin(LocalDateTime fechaFin) {
        this.fechaFin = fechaFin;
    }

    public DateTimeFormatter getParser() {
        return parser;
    }

    public void setParser(DateTimeFormatter parser) {
        this.parser = parser;
    }

}

Solution

  • It looks like there is a mismatch between the java.time class you are using and your date-time format pattern.

    All of your date-time instances are declared to be of type: LocalDateTime, so they will expect text values passed to the parse function to follow the: DateTimeFormatter.ISO_LOCAL_DATE_TIME format, which is: 2011-12-03T10:15:30.

    From the LocalDateTime JavaDoc:

    A date-time without a time-zone in the ISO-8601 calendar system, such as 2007-12-03T10:15:30.

    Notice that the format DOES include: 'T', but does NOT contain: 'Z'. And this aligns with all of the error messages that you included with your question; all of the text values referenced in those error messages contain the 'Z' character.

    If you adjust the format pattern you pass to: DateTimeFormatter.ofPattern to remove the 'Z' character, I believe your problems will be resolved.