private void CreateFeatureDefinition(KMLStyle kmlStyle, XElement feature, XElement geometry, KmlLayerContext context)
{
if (feature == null)
return; // should not happen
XNamespace kmlNS = feature.Name.Namespace;
if (feature.Name.LocalName == "Placemark")
{
// kmlStyle is null when the placemark doesn't reference any shared style (or a shared style that we are not able to download)
// in this case, use a default style
if (kmlStyle == null)
kmlStyle = new KMLStyle();
// Determine what kind of feature is present in the placemark. If an input geometry is present, then the
// style has already been determined and this method is being called recursively for each child element
// of a multi-geometry placemarker.
XElement geomElement = null;
if (geometry != null)
{
geomElement = geometry;
}
else
{
geomElement = GetFeatureType(feature);
// Override any settings from the inline style "Style" node
XElement styleElement = feature.Element(kmlNS + "Style");
if (styleElement != null)
{
GetStyle(styleElement, kmlStyle);
}
}
PlacemarkDescriptor fd = null;
if (geomElement != null && geomElement.Name != null)
{
switch (geomElement.Name.LocalName)
{
case "Point":
fd = ExtractPoint(kmlStyle, geomElement);
break;
case "LineString":
fd = ExtractPolyLine(kmlStyle, geomElement);
break;
case "LinearRing":
fd = ExtractLinearRing(kmlStyle, geomElement);
break;
case "Polygon":
fd = ExtractPolygon(kmlStyle, geomElement);
break;
case "MultiGeometry":
foreach (XElement item in geomElement.Elements())
{
// Use recursion to walk the hierarchy of embedded definitions
CreateFeatureDefinition(kmlStyle, feature, item, context);
}
break;
case "LatLonBox":
ExtractFeatureStyleInfo(kmlStyle, feature);
fd = ExtractLatLonBox(kmlStyle, geomElement);
break;
}
// If a feature definition was created, then assign timeextent, attributes and add to collection
if (fd != null)
{
fd.TimeExtent = ExtractTimeExtent(feature, fd.Attributes);
if (fd.Geometry != null)
fd.Geometry.SpatialReference = new SpatialReference(4326);
XElement descElement = feature.Element(kmlNS + "description");
if (descElement != null)
fd.Attributes.Add("description", descElement.Value);
XElement nameElement = feature.Element(kmlNS + "name");
if (nameElement != null)
fd.Attributes.Add("name", nameElement.Value);
if (atomNS != null)
{
// Initialize to parent value
Uri atomHrefValue = context.AtomHref;
// If node exists, has attributes, and can be successfully extracted, then extract
// this value.
XElement atomHrefElement = feature.Element(atomNS + "link");
if (atomHrefElement != null && atomHrefElement.HasAttributes)
{
string tempHref = GetAtomHref(atomHrefElement);
if (!String.IsNullOrEmpty(tempHref))
atomHrefValue = new Uri(tempHref);
}
// If a value was extracted or assigned from a parent, then add to attributes
if (atomHrefValue != null)
fd.Attributes.Add("atomHref", atomHrefValue);
// AtomAuthor : Initialize to parent value
string atomValue = context.AtomAuthor;
// If node exists, has attributes, and can be successfully extracted, then extract
// this value.
XElement atomAuthorElement = feature.Element(atomNS + "author");
if (atomAuthorElement != null)
{
string tempAuthor = GetAtomAuthor(atomAuthorElement);
if (!String.IsNullOrEmpty(tempAuthor))
atomValue = tempAuthor;
}
// If a value was extracted or assigned from a parent, then add to attributes
if (!String.IsNullOrEmpty(atomValue))
fd.Attributes.Add("atomAuthor", atomValue);
}
// Extract extended information
XElement extendedDataElement = feature.Element(kmlNS + "ExtendedData");
if (extendedDataElement != null)
{
List<KmlExtendedData> extendedList = new List<KmlExtendedData>();
IEnumerable<XElement> dataElements =
from e in extendedDataElement.Descendants(kmlNS + "Data")
select e;
foreach (XElement data in dataElements)
{
XAttribute name = data.Attribute("name");
if (name != null)
{
KmlExtendedData listItem = new KmlExtendedData();
listItem.Name = name.Value;
foreach (XElement dataChild in data.Descendants())
{
if (dataChild.Name == kmlNS + "displayName")
listItem.DisplayName = dataChild.Value;
else if (dataChild.Name == kmlNS + "value")
listItem.Value = dataChild.Value;
}
extendedList.Add(listItem);
}
}
if (extendedList.Count > 0)
fd.Attributes.Add("extendedData", extendedList);
}
featureDefs.AddPlacemark(fd);
}
}
}
else if (feature.Name.LocalName == "GroundOverlay")
{
XElement latLonBoxElement = feature.Element(kmlNS + "LatLonBox");
if (latLonBoxElement != null)
{
GroundOverlayDescriptor fd = new GroundOverlayDescriptor
{
Envelope = ExtractEnvelope(latLonBoxElement),
TimeExtent = ExtractTimeExtent(feature)
};
XElement rotationElement = latLonBoxElement.Element(kmlNS + "rotation");
if (rotationElement != null)
fd.Rotation = GetDoubleValue(rotationElement);
XElement colorElement = feature.Element(kmlNS + "color");
if (colorElement != null)
fd.Color = GetColorFromHexString(colorElement.Value);
else
fd.Color = System.Windows.Media.Colors.White; // Default = white
XElement iconElement = feature.Element(kmlNS + "Icon");
if (iconElement != null)
{
XElement href = iconElement.Element(kmlNS + "href");
if (href != null)
{
fd.IconHref = href.Value;
}
}
featureDefs.AddGroundOverlay(fd);
}
}
}