/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/Model/load.py
ViewVC logotype

Contents of /branches/WIP-pyshapelib-bramz/Thuban/Model/load.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 737 - (show annotations)
Fri Apr 25 09:12:17 2003 UTC (21 years, 10 months ago) by jonathan
Original Path: trunk/thuban/Thuban/Model/load.py
File MIME type: text/x-python
File size: 12763 byte(s)
(XMLReader.GetFilename): Renamed from XMLReader.GetFileName.
(SessionLoader): Added support for loading projection tags that
        appear inside a layer.

1 # Copyright (C) 2001, 2002, 2003 by Intevation GmbH
2 # Authors:
3 # Jan-Oliver Wagner <[email protected]>
4 # Bernhard Herzog <[email protected]>
5 # Jonathan Coles <[email protected]>
6 #
7 # This program is free software under the GPL (>=v2)
8 # Read the file COPYING coming with GRASS for details.
9
10 """
11 Parser for thuban session files.
12 """
13
14 __version__ = "$Revision$"
15
16 import string, os
17
18 import xml.sax
19 import xml.sax.handler
20 from xml.sax import make_parser, ErrorHandler, SAXNotRecognizedException
21
22 from Thuban import _
23 from Thuban.common import *
24
25 from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
26 FIELDTYPE_STRING
27
28 from Thuban.Model.session import Session
29 from Thuban.Model.map import Map
30 from Thuban.Model.layer import Layer
31 from Thuban.Model.color import Color
32 from Thuban.Model.proj import Projection
33 from Thuban.Model.classification import Classification, \
34 ClassGroupDefault, ClassGroupSingleton, ClassGroupRange, ClassGroupMap, \
35 ClassGroupProperties
36
37
38 def parse_color(color):
39 """Return the color object for the string color.
40
41 Color may be either 'None' or of the form '#RRGGBB' in the usual
42 HTML color notation
43 """
44 color = string.strip(color)
45 if color == "None":
46 result = Color.Transparent
47 elif color[0] == '#':
48 if len(color) == 7:
49 r = string.atoi(color[1:3], 16) / 255.0
50 g = string.atoi(color[3:5], 16) / 255.0
51 b = string.atoi(color[5:7], 16) / 255.0
52 result = Color(r, g, b)
53 else:
54 raise ValueError(_("Invalid hexadecimal color specification %s")
55 % color)
56 else:
57 raise ValueError(_("Invalid color specification %s") % color)
58 return result
59
60
61 class XMLReader(xml.sax.handler.ContentHandler):
62
63 # Dictionary mapping element names (or (URI, element name) pairs for
64 # documents using namespaces) to method names. The methods should
65 # accept the same parameters as the startElement (or startElementNS)
66 # methods. The start_dispatcher is used by the default startElement
67 # and startElementNS methods to call a method for the open tag of an
68 # element.
69 start_dispatcher = {}
70
71 # end_dispatcher works just like start_dispatcher but it's used by
72 # endElement and endElementNS. The method whose names it maps to
73 # should accept the same parameters as endElement and endElementNS.
74 end_dispatcher = {}
75
76
77 def __init__(self):
78 self.chars = ''
79 self.__parser = None
80 self.__directory = ""
81 self.__dispatchers = {}
82
83 def read(self, file_or_filename):
84
85 if hasattr(file_or_filename, "read"):
86 # it's a file object
87 self.__directory = ""
88 self.__file = file_or_filename
89 else:
90 filename = file_or_filename
91 self.__directory = os.path.dirname(filename)
92 self.__file = open(filename)
93
94 if self.__parser is None:
95 self.__parser = make_parser()
96 self.__parser.setContentHandler(self)
97 self.__parser.setErrorHandler(ErrorHandler())
98 self.__parser.setFeature(xml.sax.handler.feature_namespaces, 1)
99
100 #
101 # Well, this isn't pretty, but it appears that if you
102 # use Python 2.2 without the site-package _xmlplus then
103 # the following will fail, and without them it will work.
104 # However, if you do have the site-package and you don't
105 # call these functions, the reader raises an exception
106 #
107 # The reason we set these to 0 in the first place is
108 # because there is an unresolved issue with external
109 # entities causing an exception in the reader
110 #
111 try:
112 self.__parser.setFeature(xml.sax.handler.feature_validation,0)
113 self.__parser.setFeature(xml.sax.handler.feature_external_ges,0)
114 self.__parser.setFeature(xml.sax.handler.feature_external_pes,0)
115 except SAXNotRecognizedException:
116 pass
117
118 self.__parser.parse(self.__file)
119
120 self.close()
121
122 def close(self):
123 self.__file.close()
124
125 def GetFilename(self):
126 if hasattr(self.__file, "name"):
127 return self.__file.name
128
129 return ""
130
131 def GetDirectory(self):
132 return self.__directory
133
134
135 def AddDispatchers(self, dict):
136 """Add the function names that should be used to process XML tags.
137
138 dict -- a dictionary whose keys are XML tag strings and whose values
139 are pairs of strings such that the first string is
140 the name of the function that should be called when the
141 XML tag opens and the second string is the name of the
142 function that should be called when the XML tag closes.
143 If a pair element is None, no function is called.
144 """
145
146 self.__dispatchers.update(dict)
147
148 def startElementNS(self, name, qname, attrs):
149 """Call the method given for name in self.start_dispatcher
150 """
151 if name[0] is None:
152 method_name = self.__dispatchers.get(name[1])
153 else:
154 # Dispatch with namespace
155 method_name = self.__dispatchers.get(name)
156 if method_name is not None and method_name[0] is not None:
157 getattr(self, method_name[0])(name, qname, attrs)
158
159 def endElementNS(self, name, qname):
160 """Call the method given for name in self.end_dispatcher
161 """
162 if name[0] is None:
163 method_name = self.__dispatchers.get(name[1])
164 else:
165 # Dispatch with namespace
166 method_name = self.__dispatchers.get(name)
167 if method_name is not None and method_name[1] is not None:
168 getattr(self, method_name[1])(name, qname)
169
170 class SessionLoader(XMLReader):
171
172 def __init__(self):
173 """Inititialize the Sax handler."""
174 XMLReader.__init__(self)
175
176 self.theSession = None
177 self.aMap = None
178 self.aLayer = None
179
180 XMLReader.AddDispatchers(self,
181 {'session' : ("start_session", "end_session"),
182 'map' : ("start_map", "end_map"),
183 'projection' : ("start_projection", "end_projection"),
184 'parameter' : ("start_parameter", None),
185 'layer' : ("start_layer", "end_layer"),
186 'classification': ("start_classification", "end_classification"),
187 'clnull' : ("start_clnull", "end_clnull"),
188 'clpoint' : ("start_clpoint", "end_clpoint"),
189 'clrange' : ("start_clrange", "end_clrange"),
190 'cldata' : ("start_cldata", "end_cldata"),
191 'table' : ("start_table", "end_table"),
192 'labellayer' : ("start_labellayer", None),
193 'label' : ("start_label", None)})
194
195 def start_session(self, name, qname, attrs):
196 self.theSession = Session(attrs.get((None, 'title'), None))
197
198 def end_session(self, name, qname):
199 pass
200
201 def start_map(self, name, qname, attrs):
202 """Start a map."""
203 self.aMap = Map(attrs.get((None, 'title'), None))
204 self.__projReceiver = self.aMap
205
206 def end_map(self, name, qname):
207 self.theSession.AddMap(self.aMap)
208 self.__projReceiver = None
209
210 def start_projection(self, name, qname, attrs):
211 self.ProjectionParams = [ ]
212
213 def end_projection(self, name, qname):
214 self.__projReceiver.SetProjection(Projection(self.ProjectionParams))
215
216 def start_parameter(self, name, qname, attrs):
217 s = attrs.get((None, 'value'))
218 s = str(s) # we can't handle unicode in proj
219 self.ProjectionParams.append(s)
220
221 def start_layer(self, name, qname, attrs, layer_class = Layer):
222 """Start a layer
223
224 Instantiate a layer of class layer_class from the attributes in
225 attrs which may be a dictionary as well as the normal SAX attrs
226 object and bind it to self.aLayer.
227 """
228 title = attrs.get((None, 'title'), "")
229 filename = attrs.get((None, 'filename'), "")
230 filename = os.path.join(self.GetDirectory(), filename)
231 fill = parse_color(attrs.get((None, 'fill'), "None"))
232 stroke = parse_color(attrs.get((None, 'stroke'), "#000000"))
233 stroke_width = int(attrs.get((None, 'stroke_width'), "1"))
234 self.aLayer = layer_class(title,
235 self.theSession.OpenShapefile(filename),
236 fill = fill, stroke = stroke,
237 lineWidth = stroke_width)
238
239 self.__projReceiver = self.aLayer
240
241 def end_layer(self, name, qname):
242 self.aMap.AddLayer(self.aLayer)
243 self.__projReceiver = None
244
245 def start_classification(self, name, qname, attrs):
246 field = attrs.get((None, 'field'), None)
247
248 fieldType = attrs.get((None, 'field_type'), None)
249 dbFieldType = self.aLayer.GetFieldType(field)
250
251 if fieldType != dbFieldType:
252 raise ValueError(_("xml field type differs from database!"))
253
254 # setup conversion routines depending on the kind of data
255 # we will be seeing later on
256 if fieldType == FIELDTYPE_STRING:
257 self.conv = str
258 elif fieldType == FIELDTYPE_INT:
259 self.conv = lambda p: int(float(p))
260 elif fieldType == FIELDTYPE_DOUBLE:
261 self.conv = float
262
263 self.aLayer.GetClassification().SetField(field)
264
265
266 def end_classification(self, name, qname):
267 pass
268
269 def start_clnull(self, name, qname, attrs):
270 self.cl_group = ClassGroupDefault()
271 self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
272 self.cl_prop = ClassGroupProperties()
273
274 def end_clnull(self, name, qname):
275 self.cl_group.SetProperties(self.cl_prop)
276 self.aLayer.GetClassification().SetDefaultGroup(self.cl_group)
277 del self.cl_group, self.cl_prop
278
279 def start_clpoint(self, name, qname, attrs):
280 attrib_value = attrs.get((None, 'value'), "0")
281
282 #try:
283 #value = Str2Num(attrib_value)
284 #except:
285 #value = attrib_value
286
287 value = self.conv(attrib_value)
288
289 self.cl_group = ClassGroupSingleton(value)
290 self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
291 self.cl_prop = ClassGroupProperties()
292
293
294 def end_clpoint(self, name, qname):
295 self.cl_group.SetProperties(self.cl_prop)
296 self.aLayer.GetClassification().AppendGroup(self.cl_group)
297 del self.cl_group, self.cl_prop
298
299 def start_clrange(self, name, qname, attrs):
300
301 try:
302 min = self.conv(attrs.get((None, 'min'), "0"))
303 max = self.conv(attrs.get((None, 'max'), "0"))
304 #min = Str2Num(attrs.get((None, 'min'), "0"))
305 #max = Str2Num(attrs.get((None, 'max'), "0"))
306 except ValueError:
307 raise ValueError(_("Classification range is not a number!"))
308
309 self.cl_group = ClassGroupRange(min, max)
310 self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
311 self.cl_prop = ClassGroupProperties()
312
313
314 def end_clrange(self, name, qname):
315 self.cl_group.SetProperties(self.cl_prop)
316 self.aLayer.GetClassification().AppendGroup(self.cl_group)
317 del self.cl_group, self.cl_prop
318
319 def start_cldata(self, name, qname, attrs):
320 self.cl_prop.SetLineColor(
321 parse_color(attrs.get((None, 'stroke'), "None")))
322 self.cl_prop.SetLineWidth(
323 int(attrs.get((None, 'stroke_width'), "0")))
324 self.cl_prop.SetFill(parse_color(attrs.get((None, 'fill'), "None")))
325
326 def end_cldata(self, name, qname):
327 pass
328
329 def start_table(self, name, qname, attrs):
330 #print "table title: %s" % attrs.get('title', None)
331 pass
332
333 def end_table(self, name, qname):
334 pass
335
336 def start_labellayer(self, name, qname, attrs):
337 self.aLayer = self.aMap.LabelLayer()
338
339 def start_label(self, name, qname, attrs):
340 x = float(attrs[(None, 'x')])
341 y = float(attrs[(None, 'y')])
342 text = attrs[(None, 'text')]
343 halign = attrs[(None, 'halign')]
344 valign = attrs[(None, 'valign')]
345 self.aLayer.AddLabel(x, y, text, halign = halign, valign = valign)
346
347 def characters(self, chars):
348 pass
349
350
351 def load_session(filename):
352 """Load a Thuban session from the file object file"""
353
354 handler = SessionLoader()
355 handler.read(filename)
356
357 session = handler.theSession
358 # Newly loaded session aren't modified
359 session.UnsetModified()
360
361 return session
362

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26