source: DPPP/kml/csml2kml/python/prototypes/KMLDocument.py @ 3291

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/DPPP/kml/csml2kml/python/prototypes/KMLDocument.py@3291
Revision 3291, 7.4 KB checked in by mkochan, 13 years ago (diff)

Made other prototypes use KMLDocument-encapsulated functionality. Tested using these prototypes.

Line 
1from cElementTree import ElementTree, Element, SubElement, XML
2
3class KMLDocument:
4
5    def __init__(self, name, styles):
6
7        self.name = name
8        self.styles = styles
9        self.elements = []
10
11    def save(self, outputFilename):
12
13        # Auxiliary function, indents XML
14        def _indentXML(elem, level=0):
15            i = "\n" + level * "  "
16            if len(elem):
17                if not elem.text or not elem.text.strip():
18                    elem.text = i + "  "
19                for child in elem:
20                    _indentXML(child, level+1)
21                if not child.tail or not child.tail.strip():
22                    child.tail = i
23                if not elem.tail or not elem.tail.strip():
24                    elem.tail = i
25            else:
26                if level and (not elem.tail or not elem.tail.strip()):
27                    elem.tail = i
28
29        # Create an element to hold the document
30        self.documentElement = Element('Document')
31        SubElement(self.documentElement, 'name').text = self.name
32        SubElement(self.documentElement, 'open').text = '0'
33
34        # Build the associated styles
35        for style in self.styles:
36            self.documentElement.append( style.build() )
37
38        # Build the sub-elements
39        for element in self.elements:
40            self.documentElement.append( element.build() )
41
42        # Attach the Document element as a subelement of a root 'kml' element
43        rootElement=Element('kml', xmlns='http://earth.google.com/kml/2.2')
44        rootElement.append(self.documentElement)
45        _indentXML(rootElement)
46
47        # Write the KML document to a file
48        elementTree = ElementTree(rootElement)       
49        kmlFile = open(outputFilename, 'w')
50        elementTree.write(kmlFile)
51        kmlFile.close()
52
53# Abstract class
54class KMLElement:
55    def build(self):
56        raise NotImplementedError("Abstract method, to be overriden by child classes")
57
58class KMLStyle(KMLElement):
59
60    def __init__(self, id, iconURL = None, balloonTemplate = None, listItemType = None):
61        self.id = id
62        self.iconURL = iconURL
63        self.balloonTemplate = balloonTemplate
64        if listItemType:
65            allowedValues =  ['check', 'checkOffOnly', 'checkHideChildren', 'radioFolder']
66            if not listItemType in allowedValues:
67                raise ValueError('listItemType not among allowed values: ' + str(allowedValues))
68        self.listItemType = listItemType
69
70    def build(self):
71
72        styleElement = Element('Style')
73        styleElement.set('id', self.id)
74
75        # If specified, build the IconStyle element -- for assigning an icon to station placemarks
76        if self.iconURL:
77            iconStyleElement = SubElement(styleElement, 'IconStyle')
78            SubElement(iconStyleElement, 'scale').text = '1.2'
79            iconElement = SubElement(iconStyleElement, 'Icon')
80            SubElement(iconElement, 'href').text = self.iconURL
81
82        # If specified, build the BalloonStyle sub-element -- an HTML template for the balloons
83        if self.balloonTemplate:
84            balloonStyleElement = SubElement(styleElement, 'BalloonStyle')
85            SubElement(balloonStyleElement, 'text').text = self.balloonTemplate
86
87        # If specified, build the ListStyle sub-element -- which determines how the associated lists
88        # in the left-hand side of the Google Earth screen are going to display/behave
89        if self.listItemType:
90            listStyleElement = SubElement(styleElement, 'ListStyle')
91            SubElement(listStyleElement, 'listItemType').text = self.listItemType
92       
93        return styleElement
94
95# Defined for convenience
96def createDefaultPlacemarKMLStyle(id = 'default_placemark_style',
97                                  iconURL = 'http://maps.google.com/mapfiles/kml/shapes/target.png',
98                                  balloonTemplate = ''):
99    return KMLStyle(id, iconURL, balloonTemplate)
100
101class KMLPlacemark(KMLElement):
102   
103    def __init__(self, id, name, lon, lat, styleID = None, data=None):
104        self.id = id
105        self.name = name
106        self.lon = lon
107        self.lat = lat
108        self.styleID = styleID
109        self.data = data
110
111    def build(self):
112        placemarkElement = Element('Placemark')
113        SubElement(placemarkElement, 'name').text = self.name
114        SubElement(placemarkElement, 'open').text = '0'
115        if self.styleID:
116            SubElement(placemarkElement, 'styleUrl').text = '#' + self.styleID
117
118        lookAtElement = SubElement(placemarkElement, 'LookAt')
119        SubElement(lookAtElement, 'longitude').text = str(self.lon)
120        SubElement(lookAtElement, 'latitude').text = str(self.lat)
121
122        pointElement = SubElement(placemarkElement, 'Point')
123        SubElement(pointElement, 'coordinates').text = '%f,%f,%f' % (self.lon, self.lat, 0.)
124
125        # If the "data" dictionary is provided, create the additional <ExtendedData> element,
126        # which contains specific data items, which will be automatically substituted
127        # for placemarks in the balloon template when the user views the document in Google Earth.
128        if self.data:
129            extendedDataElement = SubElement(placemarkElement, 'ExtendedData')
130            for key in self.data:
131                dataElement = SubElement(extendedDataElement, 'Data')
132                dataElement.set('name', key)
133                value = self.data[key]
134                value = value.replace('#ID#', self.id)
135                value = value.replace('#NAME#', self.name)
136                value = value.replace('#LON#', str(self.lon))
137                value = value.replace('#LAT#', str(self.lat))
138                SubElement(dataElement, 'value').text = value
139
140        return placemarkElement
141
142class KMLFolder(KMLElement):
143
144    def __init__(self, name, children, styleID = None, region = None):
145        self.name = name
146        self.children = children
147        self.styleID = styleID
148        self.region = region
149
150    def build(self):
151        folderElement = Element('Folder')
152        if self.styleID:
153            SubElement(folderElement, 'styleUrl').text = '#' + self.styleID
154        SubElement(folderElement, 'name').text = self.name
155        if self.region:
156            if not isinstance(self.region, KMLRegion):
157                raise TypeError('Region not a KMLRegion')
158            folderElement.append( self.region.build() )
159        for child in self.children:
160            if not isinstance(child, KMLElement):
161                raise TypeError('Child does not have a KMLElement base class')
162            folderElement.append( child.build() )
163        return folderElement
164
165class KMLRegion(KMLElement):
166   
167    def __init__(self, west, south, east, north, minLodPixels = 64, maxLodPixels = -1):
168        self.west = west
169        self.south = south
170        self.east = east
171        self.north = north
172        self.minLodPixels = minLodPixels
173        self.maxLodPixels = maxLodPixels
174
175    def build(self):
176
177        llabElement = Element('LatLonAltBox')
178        SubElement(llabElement, 'west').text = str(self.west)
179        SubElement(llabElement, 'south').text = str(self.south)
180        SubElement(llabElement, 'east').text = str(self.east)
181        SubElement(llabElement, 'north').text = str(self.north)
182
183        lodElement = Element('Lod')
184        SubElement(lodElement, 'minLodPixels').text = str(self.minLodPixels)
185        SubElement(lodElement, 'maxLodPixels').text = str(self.maxLodPixels)
186
187        regionElement = Element('Region')
188        regionElement.append(llabElement)
189        regionElement.append(lodElement)
190        return regionElement
Note: See TracBrowser for help on using the repository browser.