package org.androad.sys.ors.lus.openrouteservice;
import java.util.ArrayList;
import org.osmdroid.util.GeoPoint;
import org.androad.sys.ors.adt.Error;
import org.androad.sys.ors.adt.GeocodedAddress;
import org.androad.sys.ors.adt.lus.Country;
import org.androad.sys.ors.exceptions.ORSException;
import org.androad.util.constants.Constants;
import org.androad.util.constants.TimeConstants;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import android.util.Log;
/**
* @author Nicolas Gramlich
* Parses XML-Data like:
* <pre><?xml version="1.0" encoding="UTF-8"?>
* <xls:XLS xmlns:xls="http://www.opengis.net/xls" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gml="http://www.opengis.net/gml" version="1.1" xsi:schemaLocation="http://www.opengis.net/xls http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd">
* <xls:ResponseHeader xsi:type="xls:ResponseHeaderType"/>
* <xls:Response xsi:type="xls:ResponseType" requestID="123456789" version="1.1" numberOfResponses="1">
* <xls:GeocodeResponse xsi:type="xls:GeocodeResponseType">
* <xls:GeocodeResponseList numberOfGeocodedAddresses="1">
* <xls:GeocodedAddress>
* <gml:Point>
* <gml:pos srsName="EPSG:4326">7.0986258 50.7323634</gml:pos>
* </gml:Point>
* <xls:Address countryCode="de">
* <xls:StreetAddress>
* <xls:Street officialName="Maximilianstrasse"/>
* </xls:StreetAddress>
* <xls:Place type="CountrySubdivision">Nordrhein-Westfalen</xls:Place>
* <xls:Place type="Municipality">Bonn</xls:Place>
* <xls:PostalCode>53115</xls:PostalCode>
* </xls:Address>
* <xls:GeocodeMatchCode accuracy="0.9"/>
* </xls:GeocodedAddress>
* </xls:GeocodeResponseList>
* </xls:GeocodeResponse>
* </xls:Response>
* </xls:XLS></pre>
*
*/
public class OpenRouteServiceLUSGeocodeParser extends DefaultHandler implements TimeConstants, Constants{
// ====================================
// Constants
// ====================================
protected static final int LATITUDE_OVERMAX = (int)(81 * 1E6);
protected static final int LONGITUDE_OVERMAX = (int)(181 * 1E6);
// ====================================
// Fields
// ====================================
private final ArrayList<Error> mErrors = new ArrayList<Error>();
private ArrayList<GeocodedAddress> mAddresses;
private boolean inXLS = false;
private boolean inResponseHeader = false;
private boolean inResponse = false;
private boolean inGeocodeResponse = false;
private boolean inGeocodeResponseList = false;
private boolean inGeocodedAddress = false;
private boolean inAddress = false;
private boolean inStreetAddress = false;
private boolean inStreet = false;
private boolean inPlaceCountrySubdivision = false;
private boolean inPlaceMunicipality = false;
private boolean inPostalCode = false;
private boolean inGeocodeMatchCode = false;
private boolean inPoint = false;
private boolean inPos = false;
private GeocodedAddress mTmpGeocodedAddress;
// ===========================================================
// Getter & Setter
// ===========================================================
public ArrayList<Error> getErrors(){
return this.mErrors;
}
public ArrayList<GeocodedAddress> getAddresses() throws ORSException{
if(this.mErrors != null && this.mErrors.size() > 0) {
throw new ORSException(this.mErrors);
}
return this.mAddresses;
}
// ====================================
// Methods from Superclasses
// ====================================
@Override
public void startDocument() throws SAXException {
this.mAddresses = new ArrayList<GeocodedAddress>();
super.startDocument();
}
@Override
public void startElement(final String uri, final String localName, final String name, final Attributes attributes) throws SAXException {
if(localName.equals("Error") || name.equals("Error")){
final String errorCode = attributes.getValue("", "errorCode");
final String severity = attributes.getValue("", "severity");
final String locationPath = attributes.getValue("", "locationPath");
final String message = attributes.getValue("", "message");
this.mErrors.add(new org.androad.sys.ors.adt.Error(errorCode, severity, locationPath, message));
}
this.sb.setLength(0);
if(localName.equals("XLS")){
this.inXLS = true;
} else if(localName.equals("ResponseHeader")){
this.inResponseHeader = true;
} else if(localName.equals("Response")){
this.inResponse = true;
} else if(localName.equals("GeocodeResponse")){
this.inGeocodeResponse = true;
} else if(localName.equals("GeocodeResponseList")){
this.inGeocodeResponseList = true;
} else if(localName.equals("GeocodedAddress")){
this.inGeocodedAddress = true;
} else if(localName.equals("Point")){
this.inPoint = true;
} else if(localName.equals("pos")){
this.inPos = true;
} else if(localName.equals("Address")){
this.inAddress = true;
final String countryCode = attributes.getValue("", "countryCode");
if(countryCode != null) {
this.mTmpGeocodedAddress.setNationality(Country.fromAbbreviation(countryCode));
}
} else if(localName.equals("StreetAddress")){
this.inStreetAddress = true;
} else if(localName.equals("Street")){
this.inStreet = true;
final String officialName = attributes.getValue("", "officialName");
if(officialName != null) {
this.mTmpGeocodedAddress.setStreetNameOfficial(officialName);
}
} else if(localName.equals("Place")){
final String type = attributes.getValue("", "type");
if(type.compareTo("CountrySubdivision") == 0){
this.inPlaceCountrySubdivision = true;
}else if(type.compareTo("Municipality") == 0){
this.inPlaceMunicipality = true;
}
} else if(localName.equals("PostalCode")){
this.inPostalCode = true;
} else if(localName.equals("GeocodeMatchCode")){
this.inGeocodeMatchCode = true;
final String accuracy = attributes.getValue("", "accuracy");
if(accuracy != null) {
this.mTmpGeocodedAddress.setAccuracy(Float.parseFloat(accuracy));
}
} else {
Log.w(DEBUGTAG, "Unexpected tag: '" + name + "'");
}
super.startElement(uri, localName, name, attributes);
}
protected StringBuilder sb = new StringBuilder();
@Override
public void characters(final char[] chars, final int start, final int length) throws SAXException {
this.sb.append(chars, start, length);
super.characters(chars, start, length);
}
@Override
public void endElement(final String uri, final String localName, final String name) throws SAXException {
if(localName.equals("XLS")){
this.inXLS = false;
} else if(localName.equals("ResponseHeader")){
this.inResponseHeader = false;
} else if(localName.equals("Response")){
this.inResponse = false;
} else if(localName.equals("GeocodeResponse")){
this.inGeocodeResponse = false;
} else if(localName.equals("GeocodeResponseList")){
this.inGeocodeResponseList = false;
} else if(localName.equals("GeocodedAddress")){
this.inGeocodedAddress = false;
} else if(localName.equals("Point")){
this.inPoint = false;
} else if(localName.equals("pos")){
this.inPos = false;
final GeoPoint gp = GeoPoint.fromInvertedDoubleString(this.sb.toString(), ' ');
this.mTmpGeocodedAddress = new GeocodedAddress(gp);
this.mAddresses.add(this.mTmpGeocodedAddress);
} else if(localName.equals("Address")){
this.inAddress = false; // CC
} else if(localName.equals("StreetAddress")){
this.inStreetAddress = false;
} else if(localName.equals("Street")){
this.inStreet = false;
} else if(localName.equals("Place")){
if(this.inPlaceCountrySubdivision){
this.inPlaceCountrySubdivision = false;
this.mTmpGeocodedAddress.setCountrySubdivision(this.sb.toString());
}else if(this.inPlaceMunicipality){
this.inPlaceMunicipality = false;
this.mTmpGeocodedAddress.setMunicipality(this.sb.toString());
}
} else if(localName.equals("PostalCode")){
this.inPostalCode = false;
this.mTmpGeocodedAddress.setPostalCode(this.sb.toString());
} else if(localName.equals("GeocodeMatchCode")){
this.inGeocodeMatchCode = false;
} else {
Log.w(DEBUGTAG, "Unexpected end-tag: '" + name + "'");
}
// Reset the stringbuffer
this.sb.setLength(0);
super.endElement(uri, localName, name);
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
}