/[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 763 - (show annotations)
Tue Apr 29 10:55:26 2003 UTC (21 years, 10 months ago) by bh
Original Path: trunk/thuban/Thuban/Model/load.py
File MIME type: text/x-python
File size: 12656 byte(s)
(XMLReader.__init__, XMLReader.read): Turn
the __parser instance variable into a normal local variable in
read. It's only used there and read will never be called more than
once. Plus it introduces a reference cycle that keeps can keep the
session object alive for a long time.

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.__directory = ""
80 self.__dispatchers = {}
81
82 def read(self, file_or_filename):
83
84 if hasattr(file_or_filename, "read"):
85 # it's a file object
86 self.__directory = ""
87 self.__file = file_or_filename
88 else:
89 filename = file_or_filename
90 self.__directory = os.path.dirname(filename)
91 self.__file = open(filename)
92
93 parser = make_parser()
94 parser.setContentHandler(self)
95 parser.setErrorHandler(ErrorHandler())
96 parser.setFeature(xml.sax.handler.feature_namespaces, 1)
97
98 #
99 # Well, this isn't pretty, but it appears that if you
100 # use Python 2.2 without the site-package _xmlplus then
101 # the following will fail, and without them it will work.
102 # However, if you do have the site-package and you don't
103 # call these functions, the reader raises an exception
104 #
105 # The reason we set these to 0 in the first place is
106 # because there is an unresolved issue with external
107 # entities causing an exception in the reader
108 #
109 try:
110 parser.setFeature(xml.sax.handler.feature_validation,0)
111 parser.setFeature(xml.sax.handler.feature_external_ges,0)
112 parser.setFeature(xml.sax.handler.feature_external_pes,0)
113 except SAXNotRecognizedException:
114 pass
115
116 parser.parse(self.__file)
117
118 self.close()
119
120 def close(self):
121 self.__file.close()
122
123 def GetFilename(self):
124 if hasattr(self.__file, "name"):
125 return self.__file.name
126
127 return ""
128
129 def GetDirectory(self):
130 return self.__directory
131
132
133 def AddDispatchers(self, dict):
134 """Add the function names that should be used to process XML tags.
135
136 dict -- a dictionary whose keys are XML tag strings and whose values
137 are pairs of strings such that the first string is
138 the name of the function that should be called when the
139 XML tag opens and the second string is the name of the
140 function that should be called when the XML tag closes.
141 If a pair element is None, no function is called.
142 """
143
144 self.__dispatchers.update(dict)
145
146 def startElementNS(self, name, qname, attrs):
147 """Call the method given for name in self.start_dispatcher
148 """
149 if name[0] is None:
150 method_name = self.__dispatchers.get(name[1])
151 else:
152 # Dispatch with namespace
153 method_name = self.__dispatchers.get(name)
154 if method_name is not None and method_name[0] is not None:
155 getattr(self, method_name[0])(name, qname, attrs)
156
157 def endElementNS(self, name, qname):
158 """Call the method given for name in self.end_dispatcher
159 """
160 if name[0] is None:
161 method_name = self.__dispatchers.get(name[1])
162 else:
163 # Dispatch with namespace
164 method_name = self.__dispatchers.get(name)
165 if method_name is not None and method_name[1] is not None:
166 getattr(self, method_name[1])(name, qname)
167
168 class SessionLoader(XMLReader):
169
170 def __init__(self):
171 """Inititialize the Sax handler."""
172 XMLReader.__init__(self)
173
174 self.theSession = None
175 self.aMap = None
176 self.aLayer = None
177
178 XMLReader.AddDispatchers(self,
179 {'session' : ("start_session", "end_session"),
180 'map' : ("start_map", "end_map"),
181 'projection' : ("start_projection", "end_projection"),
182 'parameter' : ("start_parameter", None),
183 'layer' : ("start_layer", "end_layer"),
184 'classification': ("start_classification", "end_classification"),
185 'clnull' : ("start_clnull", "end_clnull"),
186 'clpoint' : ("start_clpoint", "end_clpoint"),
187 'clrange' : ("start_clrange", "end_clrange"),
188 'cldata' : ("start_cldata", "end_cldata"),
189 'table' : ("start_table", "end_table"),
190 'labellayer' : ("start_labellayer", None),
191 'label' : ("start_label", None)})
192
193 def start_session(self, name, qname, attrs):
194 self.theSession = Session(attrs.get((None, 'title'), None))
195
196 def end_session(self, name, qname):
197 pass
198
199 def start_map(self, name, qname, attrs):
200 """Start a map."""
201 self.aMap = Map(attrs.get((None, 'title'), None))
202 self.__projReceiver = self.aMap
203
204 def end_map(self, name, qname):
205 self.theSession.AddMap(self.aMap)
206 self.__projReceiver = None
207
208 def start_projection(self, name, qname, attrs):
209 self.ProjectionName = attrs.get((None, 'name'), None)
210 self.ProjectionParams = [ ]
211
212 def end_projection(self, name, qname):
213 self.__projReceiver.SetProjection(
214 Projection(self.ProjectionParams, self.ProjectionName))
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