""" Utility classes for working with the Keyhole Markup Language (KML). """ import sys from xml.sax.saxutils import escape class KmlObject(object): """ The base class of all KML elements, according to the reference: http://code.google.com/apis/kml/documentation/kmlreference.html Every other class in this module should derive from KmlObject. This class provides a default constructor which creates some necessary attributes, and default implementations of to_kml() and render(). The to_kml() methods of our subclasses will, in general, generate an opening tag, render themselves (whatever that means), and then generate a closing tag. A call to render() generally returns the element's text, and renders its children recursively. """ OPEN_TAG = '' CLOSE_TAG = '' def __init__(self, initial_text=''): self.children = [] self.text = initial_text def to_kml(self): kml = self.OPEN_TAG kml += self.render() kml += self.CLOSE_TAG + "\n" return kml def render(self): kml = escape(self.text) for c in self.children: kml += c.to_kml() return kml def print_kml(self): print self.OPEN_TAG self.render_to_stdout() print self.CLOSE_TAG def render_to_stdout(self): if (len(self.text) > 0): print escape(self.text) for c in self.children: c.print_kml() class Color(KmlObject): OPEN_TAG = '' CLOSE_TAG = '' class Document(KmlObject): OPEN_TAG = """ """ CLOSE_TAG = """ """ def __init__(self, initial_text=''): super(Document, self).__init__(initial_text) self.styles = [] def render(self): kml = '' for s in self.styles: kml += s.to_kml() for c in self.children: kml += c.to_kml() return kml def render_to_stdout(self): for s in self.styles: s.print_kml() for c in self.children: c.print_kml() class Description(KmlObject): OPEN_TAG = '' CLOSE_TAG = '' class Coordinates(KmlObject): OPEN_TAG = '' CLOSE_TAG = '' class LineString(KmlObject): OPEN_TAG = '' CLOSE_TAG = '' @classmethod def parse_linestrings(self, kml): """ Parse each ... block from the KML. """ linestrings = [] search_idx = kml.find(self.OPEN_TAG, 0) while (search_idx != -1): # No reason to keep the tag around. ls_start = search_idx + len(self.OPEN_TAG) ls_tag_end = kml.find(self.CLOSE_TAG, ls_start) ls = kml[ ls_start : ls_tag_end ] linestrings.append(ls) search_idx = kml.find(self.OPEN_TAG, (ls_tag_end + len(self.CLOSE_TAG))) return linestrings @classmethod def parse_coordinates_from_linestrings(self, linestrings): coords = [] for ls in linestrings: c_tag_start = ls.find(Coordinates.OPEN_TAG) c_start = c_tag_start + len(Coordinates.OPEN_TAG) c_end = ls.find(Coordinates.CLOSE_TAG) c = ls[ c_start : c_end ] coords.append(c) return coords @classmethod def tuples_from_kml(self, kml): """ Parse one or more linestrings from a KML document. Return a list of tuples. """ ls = self.parse_linestrings(kml) cs = self.parse_coordinates_from_linestrings(ls) tuples = [] for c in cs: pointstrings = c.strip().split() for point in pointstrings: components = point.strip().split(',') if (len(components) >= 2): # Project the three-dimensional vector onto the # x-y plane. I don't think we're going to run # in to any linestrings in 3d. tuples.append( (float(components[0]), float(components[1])) ) return tuples class Name(KmlObject): OPEN_TAG = '' CLOSE_TAG = '' class Placemark(KmlObject): OPEN_TAG = '' CLOSE_TAG = '' class PolyStyle(KmlObject): OPEN_TAG = '' CLOSE_TAG = '' class Style(KmlObject): OPEN_TAG = "' def __init__(self, initial_text='', initial_id=''): super(Style, self).__init__(initial_text) self.id = initial_id def to_kml(self): kml = '' kml += (self.OPEN_TAG % self.id + "\n") kml += self.render() kml += self.CLOSE_TAG + "\n" return kml def print_kml(self): print (self.OPEN_TAG % self.id) self.render_to_stdout() print self.CLOSE_TAG class StyleUrl(KmlObject): OPEN_TAG = '' CLOSE_TAG = '' class RawText(KmlObject): def to_kml(self): return self.text def print_kml(self): if (len(self.text) > 0): print self.text