package edu.illinois.geoalarm.parser;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Vector;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Queries CUMTD for real-time data, returned as XML. Then parses the XML and
* returns objects encapsulating its data
* @author GeoAlarm
*
*/
public class XMLParser
{
private static final String API_KEY = "ef23cfb988384e259056b4098c70d877";
private static final String VERSION = "v2.1";
private static String PLAN_TRIP_URL = "http://developer.cumtd.com/api/"
+ VERSION + "/xml/GetPlannedTripsByLatLon?key=" + API_KEY;
private static Document tripDoc;
/**
* gets data from query URL address
*
* @param address
* - URL query
* @return - data from query
*/
static String getData(String address)
{
URL url = null;
InputStream is = null;
BufferedReader dis;
String data = "";
String line;
try
{
url = new URL(address);
}
catch (MalformedURLException e)
{
System.err.println("ERROR: the URL is malformed. Now terminating...");
return null;
}
try
{
is = url.openStream();
}
catch (IOException e)
{
System.err.println("ERROR: cannot open stream. Now terminating...");
return null;
} // throws an IOException
dis = new BufferedReader(new InputStreamReader(is));
try
{
while ((line = dis.readLine()) != null)
{
data += line;
}
dis.close();
is.close();
}
catch (IOException e)
{
System.err.println("ERROR: unexpected error occured. Now terminating...");
return null;
}
return data;
}
/**
* Parse Trip itinerary
*
* @return Vector that contains all Itineraries
* @throws XPathExpressionException
*/
private static Vector<Itinerary> parseTrip() throws XPathExpressionException
{
Vector<Itinerary> Itineraries = new Vector<Itinerary>();
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression expr = xpath.compile("//itinerary");
Object result = expr.evaluate(tripDoc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
// traverse list of itineraries
for (int i = 0; i < nodes.getLength(); i++)
{
String startTime, endTime;
Node currentItinerary = nodes.item(i);
System.out.println(nodes.item(i).getNodeName());
NamedNodeMap itineraryAttributes = currentItinerary.getAttributes();
startTime = itineraryAttributes.getNamedItem("start_time")
.getTextContent();
endTime = itineraryAttributes.getNamedItem("end_time")
.getTextContent();
Itinerary itinerary = new Itinerary(startTime, endTime);
// get legs from current itinerary
xpath = XPathFactory.newInstance().newXPath();
expr = xpath.compile("legs/leg");
result = expr.evaluate(currentItinerary, XPathConstants.NODESET);
NodeList legNodes = // (NodeList) result;
currentItinerary.getChildNodes().item(0).getChildNodes();
// traverse legs
for (int j = 0; j < legNodes.getLength(); j++)
{
Node currentLeg = legNodes.item(j);
System.out.println(legNodes.item(j).getNodeName());
// TODO: check Leg type
NamedNodeMap legAttributes = currentLeg.getAttributes();
System.out.println("type " + legAttributes.getNamedItem("type").getTextContent());
if (!legAttributes.getNamedItem("type").getTextContent().equals("Service"))
continue;
// get service nodes
NodeList serviceNodes = currentLeg.getChildNodes().item(0).getChildNodes();
System.out.println("Number " + serviceNodes.getLength() + " NodeName " + serviceNodes.item(0).getNodeName());
NodeList serviceDetailNodes = serviceNodes.item(0).getChildNodes();
Trip begin = null, end = null;
String lat, lon, time, busName;
// traverse serviceDetails: begin,end,route,trip
for (int k = 0; k < serviceDetailNodes.getLength(); k++)
{
Node currentServiceDetailNode = serviceDetailNodes.item(k);
System.out.println("Number "+ serviceDetailNodes.getLength() + " NodeName " + serviceDetailNodes.item(k).getNodeName());
if (currentServiceDetailNode.getNodeName().equals("begin"))
{
NamedNodeMap beginAttributes = currentServiceDetailNode.getAttributes();
lat = (beginAttributes.getNamedItem("lat").getTextContent());
lon = (beginAttributes.getNamedItem("lon").getTextContent());
time = (beginAttributes.getNamedItem("time").getTextContent());
busName = null;
begin = new Trip(lat, lon, time, busName);
}
if (currentServiceDetailNode.getNodeName().equals("end"))
{
NamedNodeMap beginAttributes = currentServiceDetailNode.getAttributes();
lat = (beginAttributes.getNamedItem("lat").getTextContent());
lon = (beginAttributes.getNamedItem("lon").getTextContent());
time = (beginAttributes.getNamedItem("time").getTextContent());
busName = null;
end = new Trip(lat, lon, time, busName);
}
if (currentServiceDetailNode.getNodeName().equals("route"))
{
NamedNodeMap beginAttributes = currentServiceDetailNode.getAttributes();
busName = (beginAttributes.getNamedItem("route_short_name").getTextContent());
begin.setBusName(busName);
end.setBusName(busName);
}
}
itinerary.addLeg(begin, end);
}
Itineraries.add(itinerary);
}
return Itineraries;
}
/**
* Creates XML from a string
*
* @param xmlString A String containing XML data
* @return XML Document A Document containing XML data
* @throws SAXException
* @throws IOException
* @throws ParserConfigurationException
*/
public static Document CreateXML(String xmlString) throws SAXException,
IOException, ParserConfigurationException
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
InputSource source = new InputSource(new StringReader(xmlString));
Document document = factory.newDocumentBuilder().parse(source);
return document;
}
/**
* Creates query for trip
*
* @param origin_lat The trip origin latitude
* @param origin_lon The trip origin longitude
* @param dest_lat The trip destination latitude
* @param dest_lon The trip destination longitude
* @return query as a String
*/
public static String tripPlanner(String origin_lat, String origin_lon,
String dest_lat, String dest_lon)
{
String trip_query = PLAN_TRIP_URL;
trip_query += "&origin_lat=" + origin_lat;
trip_query += "&origin_lon=" + origin_lon;
trip_query += "&destination_lat=" + dest_lat;
trip_query += "&destination_lon=" + dest_lon;
return trip_query;
}
/**
* user function to get all Itinerary
*
* @param origin_lat The trip origin latitude
* @param origin_lon The trip origin longitude
* @param dest_lat The trip destination latitude
* @param dest_lon The trip destination longitude
* @return A Vector containing all of the Itinerary parsed
* @throws SAXException
* @throws IOException
* @throws ParserConfigurationException
* @throws XPathExpressionException
*/
public static Vector<Itinerary> getItinerary(String origin_lat, String origin_lon, String dest_lat, String dest_lon)
throws SAXException, IOException, ParserConfigurationException,
XPathExpressionException
{
String trip_url = tripPlanner(origin_lat, origin_lon, dest_lat,
dest_lon);
String tripStr = XMLParser.getData(trip_url);
Vector<Itinerary> Itineraries;
if(tripStr != null)
{
tripDoc = CreateXML(tripStr);
Itineraries = parseTrip();
}
else
{
Itineraries = new Vector<Itinerary>();
}
return Itineraries;
}
/***
* Parses and returns Itineraries for a trip
* @param origin_lat The trip origin latitude
* @param origin_lon The trip origin longitude
* @param dest_lat The trip destination latitude
* @param dest_lon The trip destination longitude
* @return A Vector containing all of the Itinerary parsed
*/
public Vector<Itinerary> getTripItinerary(String origin_lat, String origin_lon, String dest_lat, String dest_lon)
{
String trip_url = tripPlanner(origin_lat, origin_lon, dest_lat, dest_lon);
String tripStr = getData(trip_url);
try
{
setTripDoc(CreateXML(tripStr));
return parseTrip();
}
catch (XPathExpressionException e)
{
e.printStackTrace();
}
catch (SAXException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
catch (ParserConfigurationException e)
{
e.printStackTrace();
}
return null;
}
/**
* Gets a string array of available itineraries
* @param origin_lat latitude of the start
* @param origin_lon longitude of the start
* @param dest_lat latitude of the end
* @param dest_lon longitude of the end
* @return string array of itineraries
*/
public String[] getItineraryArray(String origin_lat, String origin_lon,
String dest_lat, String dest_lon)
{
Vector<Itinerary> itineraries;
String[] itineraryArray;
try {
itineraries = getItinerary(origin_lat, origin_lon, dest_lat,
dest_lon);
if (itineraries.size() == 0) {
itineraryArray = new String[1];
itineraryArray[0] = "No routes available at this time";
return itineraryArray;
}
itineraryArray = new String[itineraries.size()];
for (int i = 0; i < itineraries.size(); i++) {
Vector<Itinerary.Leg> legs = itineraries.get(i).getLegs();
itineraryArray[i] = "Start: "
+ legs.get(0).getBegin().getTime().substring(11,16) + " End: "
+ legs.get(legs.size() - 1).getEnd().getTime().substring(11,16);
}
return itineraryArray;
}
catch (XPathExpressionException e)
{
e.printStackTrace();
itineraryArray = new String[1];
itineraryArray[0] = "No routes available at this time";
}
catch (SAXException e)
{
e.printStackTrace();
itineraryArray = new String[1];
itineraryArray[0] = "No routes available at this time";
}
catch (IOException e)
{
e.printStackTrace();
itineraryArray = new String[1];
itineraryArray[0] = "No routes available at this time";
}
catch (ParserConfigurationException e)
{
e.printStackTrace();
itineraryArray = new String[1];
itineraryArray[0] = "No routes available at this time";
}
return null;
}
/**
* Retrieves the legs of a given itinerary.
* @param origin_lat latitude of the start
* @param origin_lon longitude of the start
* @param dest_lat latitude of the end
* @param dest_lon longitude of the start
* @param itinerary nth itinerary to be fetched
* @return string array of legs
*/
public String[] getLegArray(String origin_lat, String origin_lon, String dest_lat, String dest_lon, int itinerary)
{
Vector<Itinerary> itineraries;
String[] legArray;
try
{
itineraries = getItinerary(origin_lat, origin_lon, dest_lat,
dest_lon);
if (itineraries.size() <= itinerary) {
legArray = new String[1];
legArray[0] = "No routes available at this time";
return legArray;
}
Vector<Itinerary.Leg> legs = itineraries.get(itinerary).getLegs();
legArray = new String[legs.size()];
for (int j = 0; j < legs.size(); j++) {
Trip begin = legs.get(j).getBegin();
Trip end = legs.get(j).getEnd();
legArray[j] = "Bus: " + begin.getBusName() + " "
+ begin.getTime().substring(11, 16) + " - " + end.getTime().substring(11,16);
}
return legArray;
}
catch (XPathExpressionException e)
{
e.printStackTrace();
legArray = new String[1];
legArray[0] = "No routes available at this time";
}
catch (SAXException e)
{
e.printStackTrace();
legArray = new String[1];
legArray[0] = "No routes available at this time";
}
catch (IOException e)
{
e.printStackTrace();
legArray = new String[1];
legArray[0] = "No routes available at this time";
}
catch (ParserConfigurationException e)
{
e.printStackTrace();
legArray = new String[1];
legArray[0] = "No routes available at this time";
}
return legArray;
}
/**
* Sets the trip document used by the parser
* @param tripDoc The new Documents
*/
public void setTripDoc(Document tripDoc)
{
XMLParser.tripDoc = tripDoc;
}
}