package com.google.maps.android.kml;
import com.google.android.gms.maps.model.GroundOverlay;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
/**
* Parses a given KML file into KmlStyle, KmlPlacemark, KmlGroundOverlay and KmlContainer objects
*/
/* package */ class KmlParser {
private final static String STYLE = "Style";
private final static String STYLE_MAP = "StyleMap";
private final static String PLACEMARK = "Placemark";
private final static String GROUND_OVERLAY = "GroundOverlay";
private final static String CONTAINER_REGEX = "Folder|Document";
private final XmlPullParser mParser;
private final HashMap<KmlPlacemark, Object> mPlacemarks;
private final ArrayList<KmlContainer> mContainers;
private final HashMap<String, KmlStyle> mStyles;
private final HashMap<String, String> mStyleMaps;
private final HashMap<KmlGroundOverlay, GroundOverlay> mGroundOverlays;
private final static String UNSUPPORTED_REGEX = "altitude|altitudeModeGroup|altitudeMode|" +
"begin|bottomFov|cookie|displayName|displayMode|displayMode|end|expires|extrude|" +
"flyToView|gridOrigin|httpQuery|leftFov|linkDescription|linkName|linkSnippet|" +
"listItemType|maxSnippetLines|maxSessionLength|message|minAltitude|minFadeExtent|" +
"minLodPixels|minRefreshPeriod|maxAltitude|maxFadeExtent|maxLodPixels|maxHeight|" +
"maxWidth|near|NetworkLink|NetworkLinkControl|overlayXY|range|refreshMode|" +
"refreshInterval|refreshVisibility|rightFov|roll|rotationXY|screenXY|shape|sourceHref|" +
"state|targetHref|tessellate|tileSize|topFov|viewBoundScale|viewFormat|viewRefreshMode|" +
"viewRefreshTime|when";
/**
* Creates a new KmlParser object
*
* @param parser parser containing the KML file to parse
*/
/* package */ KmlParser(XmlPullParser parser) {
mParser = parser;
mPlacemarks = new HashMap<KmlPlacemark, Object>();
mContainers = new ArrayList<KmlContainer>();
mStyles = new HashMap<String, KmlStyle>();
mStyleMaps = new HashMap<String, String>();
mGroundOverlays = new HashMap<KmlGroundOverlay, GroundOverlay>();
}
/**
* Parses the KML file and stores the created KmlStyle and KmlPlacemark
*/
/* package */ void parseKml() throws XmlPullParserException, IOException {
int eventType = mParser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if (mParser.getName().matches(UNSUPPORTED_REGEX)) {
skip(mParser);
}
if (mParser.getName().matches(CONTAINER_REGEX)) {
mContainers.add(KmlContainerParser.createContainer(mParser));
}
if (mParser.getName().equals(STYLE)) {
KmlStyle style = KmlStyleParser.createStyle(mParser);
mStyles.put(style.getStyleId(), style);
}
if (mParser.getName().equals(STYLE_MAP)) {
mStyleMaps.putAll(KmlStyleParser.createStyleMap(mParser));
}
if (mParser.getName().equals(PLACEMARK)) {
mPlacemarks.put(KmlFeatureParser.createPlacemark(mParser), null);
}
if (mParser.getName().equals(GROUND_OVERLAY)) {
mGroundOverlays.put(KmlFeatureParser.createGroundOverlay(mParser), null);
}
}
eventType = mParser.next();
}
//Need to put an empty new style
mStyles.put(null, new KmlStyle());
}
/**
* @return List of styles created by the parser
*/
/* package */ HashMap<String, KmlStyle> getStyles() {
return mStyles;
}
/**
* @return A list of Kml Placemark objects
*/
/* package */ HashMap<KmlPlacemark, Object> getPlacemarks() {
return mPlacemarks;
}
/**
* @return A list of Kml Style Maps
*/
/* package */ HashMap<String, String> getStyleMaps() {
return mStyleMaps;
}
/**
* @return A list of Kml Folders
*/
/* package */ ArrayList<KmlContainer> getContainers() {
return mContainers;
}
/**
* @return A list of Ground Overlays
*/
/* package */ HashMap<KmlGroundOverlay, GroundOverlay> getGroundOverlays() {
return mGroundOverlays;
}
/**
* Skips tags from START TAG to END TAG
* @param parser XmlPullParser
*/
/*package*/ static void skip(XmlPullParser parser)
throws XmlPullParserException, IOException {
if (parser.getEventType() != XmlPullParser.START_TAG) {
throw new IllegalStateException();
}
int depth = 1;
while (depth != 0) {
switch (parser.next()) {
case XmlPullParser.END_TAG:
depth--;
break;
case XmlPullParser.START_TAG:
depth++;
break;
}
}
}
}