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; import static org.xmlpull.v1.XmlPullParser.END_TAG; import static org.xmlpull.v1.XmlPullParser.START_TAG; /** * Parses the container of a given KML file into a KmlContainer object */ /* package */ class KmlContainerParser { private final static String PROPERTY_REGEX = "name|description|visibility|open|address|phoneNumber"; private final static String CONTAINER_REGEX = "Folder|Document"; private final static String PLACEMARK = "Placemark"; private final static String STYLE = "Style"; private final static String STYLE_MAP = "StyleMap"; private final static String EXTENDED_DATA = "ExtendedData"; private final static String GROUND_OVERLAY = "GroundOverlay"; 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|overlayXY|range|" + "refreshMode|refreshInterval|refreshVisibility|rightFov|roll|rotationXY|screenXY|shape|" + "sourceHref|state|targetHref|tessellate|tileSize|topFov|viewBoundScale|viewFormat|" + "viewRefreshMode|viewRefreshTime|when"; /** * Obtains a Container object (created if a Document or Folder start tag is read by the * XmlPullParser) and assigns specific elements read from the XmlPullParser to the container. */ /* package */ static KmlContainer createContainer(XmlPullParser parser) throws XmlPullParserException, IOException { return assignPropertiesToContainer(parser); } /** * Creates a new KmlContainer objects and assigns specific elements read from the XmlPullParser * to the new KmlContainer. * * @param parser XmlPullParser object reading from a KML file * @return KmlContainer object with properties read from the XmlPullParser */ private static KmlContainer assignPropertiesToContainer(XmlPullParser parser) throws XmlPullParserException, IOException { String startTag = parser.getName(); String containerId = null; HashMap<String, String> containerProperties = new HashMap<String, String>(); HashMap<String, KmlStyle> containerStyles = new HashMap<String, KmlStyle>(); HashMap<KmlPlacemark, Object> containerPlacemarks = new HashMap<KmlPlacemark, Object>(); ArrayList<KmlContainer> nestedContainers = new ArrayList<KmlContainer>(); HashMap<String, String> containerStyleMaps = new HashMap<String, String>(); HashMap<KmlGroundOverlay, GroundOverlay> containerGroundOverlays = new HashMap<KmlGroundOverlay, GroundOverlay>(); if (parser.getAttributeValue(null, "id") != null) { containerId = parser.getAttributeValue(null, "id"); } parser.next(); int eventType = parser.getEventType(); while (!(eventType == END_TAG && parser.getName().equals(startTag))) { if (eventType == START_TAG) { if (parser.getName().matches(UNSUPPORTED_REGEX)) { KmlParser.skip(parser); } else if (parser.getName().matches(CONTAINER_REGEX)) { nestedContainers.add(assignPropertiesToContainer(parser)); } else if (parser.getName().matches(PROPERTY_REGEX)) { containerProperties.put(parser.getName(), parser.nextText()); } else if (parser.getName().equals(STYLE_MAP)) { setContainerStyleMap(parser, containerStyleMaps); } else if (parser.getName().equals(STYLE)) { setContainerStyle(parser, containerStyles); } else if (parser.getName().equals(PLACEMARK)) { setContainerPlacemark(parser, containerPlacemarks); } else if (parser.getName().equals(EXTENDED_DATA)) { setExtendedDataProperties(parser, containerProperties); } else if (parser.getName().equals(GROUND_OVERLAY)) { containerGroundOverlays .put(KmlFeatureParser.createGroundOverlay(parser), null); } } eventType = parser.next(); } return new KmlContainer(containerProperties, containerStyles, containerPlacemarks, containerStyleMaps, nestedContainers, containerGroundOverlays, containerId); } /** * Creates a new style map and assigns values from the XmlPullParser parser * and stores it into the container. */ private static void setContainerStyleMap(XmlPullParser parser, HashMap<String, String> containerStyleMap) throws XmlPullParserException, IOException { containerStyleMap.putAll(KmlStyleParser.createStyleMap(parser)); } /** * Assigns properties given as an extended data element, which are obtained from an * XmlPullParser and stores it in a container, Untyped data only, no simple data * or schema, and entity replacements of the form $[dataName] are unsupported. */ private static void setExtendedDataProperties(XmlPullParser parser, HashMap<String, String> mContainerProperties) throws XmlPullParserException, IOException { String propertyKey = null; int eventType = parser.getEventType(); while (!(eventType == END_TAG && parser.getName().equals(EXTENDED_DATA))) { if (eventType == START_TAG) { if (parser.getName().equals("Data")) { propertyKey = parser.getAttributeValue(null, "name"); } else if (parser.getName().equals("value") && propertyKey != null) { mContainerProperties.put(propertyKey, parser.nextText()); propertyKey = null; } } eventType = parser.next(); } } /** * Creates a new default Kml Style with a specified ID (given as an attribute value in the * start tag) and assigns specific elements read from the XmlPullParser to the Style. A new * style is not created if it does not have an ID. */ private static void setContainerStyle(XmlPullParser parser, HashMap<String, KmlStyle> containerStyles) throws XmlPullParserException, IOException { if (parser.getAttributeValue(null, "id") != null) { KmlStyle style = KmlStyleParser.createStyle(parser); String styleId = style.getStyleId(); containerStyles.put(styleId, style); } } /** * Creates a new placemark object and assigns specific elements read from the XmlPullParser * to the Placemark and stores this into the given Container. */ private static void setContainerPlacemark(XmlPullParser parser, HashMap<KmlPlacemark, Object> containerPlacemarks) throws XmlPullParserException, IOException { containerPlacemarks.put(KmlFeatureParser.createPlacemark(parser), null); } }