source: DPPP/kml/csml2kml/python/csml2kml/KMLDocument.py @ 3362

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

Made StationConvertor? class use the Station.py module.

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