package net.sourceforge.gpstools.utils;
import net.sourceforge.gpstools.gpx.Gpx;
import org.exolab.castor.xml.Unmarshaller;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.XMLFilterImpl;
/**
* This ContentHandler can be used to parse a stream of SAX events
* from a GPX 1.1 source.
* It implements the GPX specification rule that xsd:dateTime
* values without a time zone should be treated as UTC.
*
* @author ringler
*
*/
public class GpxHandler extends XMLFilterImpl {
private static final String GpxNamespace = "http://www.topografix.com/GPX/1/1";
private Gpx gpx;
private Unmarshaller unmarshaller;
private boolean isReadingDate = false;
private char[] dateTimeBuff = new char[32];
private int c = 0;
private boolean appendZ = false;
public GpxHandler() {
this.unmarshaller = new Unmarshaller(Gpx.class);
this.gpx = new Gpx();
unmarshaller.setObject(gpx);
super.setContentHandler(unmarshaller.createHandler());
}
/**
* @param gpx the gpx to set
*/
public void setGpx(Gpx gpx) {
this.gpx = gpx;
unmarshaller.setObject(gpx);
}
/** Throws an UnsupportedOperationException.
* @throws UnsupportedOperationException whenever you call this method.
* **/
@Override
public void setContentHandler(ContentHandler handler)
{
throw new UnsupportedOperationException();
}
/**
* @return the gpx
*/
public Gpx getGpx() {
return gpx;
}
/*
* (non-Javadoc)
*
* @see org.xml.sax.helpers.XMLFilterImpl#startElement(java.lang.String,
* java.lang.String, java.lang.String, org.xml.sax.Attributes)
*/
@Override
public void startElement(String namespaceUri, String localName,
String qualifiedName, Attributes attributes) throws SAXException {
if (GpxNamespace.equals(namespaceUri) && "time".equals(localName)) {
this.isReadingDate = true;
this.c = 0;
this.appendZ = false;
}
super.startElement(namespaceUri, localName, qualifiedName, attributes);
}
/*
* (non-Javadoc)
*
* @see org.xml.sax.helpers.XMLFilterImpl#characters(char[], int, int)
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if (this.isReadingDate) {
int max = start + length;
for (int i = start; i < max; i++) {
char charAtI = ch[i];
switch (charAtI) {
case 'T':
this.appendZ = true;
dateTimeBuff[c++] = charAtI;
break;
case '+':
case '-':
case 'z':
case 'Z':
this.appendZ = false;
dateTimeBuff[c++] = charAtI;
break;
case ' ':
case '\r':
case '\t':
case '\n':
// ignore whitespace
break;
default:
dateTimeBuff[c++] = charAtI;
break;
}
}
} else {
super.characters(ch, start, length);
}
}
/*
* (non-Javadoc)
*
* @see org.xml.sax.helpers.XMLFilterImpl#endElement(java.lang.String,
* java.lang.String, java.lang.String)
*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if (this.isReadingDate) {
assert (GpxNamespace.equals(uri) && "time".equals(localName));
this.isReadingDate = false;
if (this.appendZ) {
this.dateTimeBuff[c++] = 'Z';
}
super.characters(this.dateTimeBuff, 0, c);
}
super.endElement(uri, localName, qName);
}
}