/[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 784 - (show annotations)
Tue Apr 29 17:30:18 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: 12521 byte(s)
Remove Thuban.common import and commented code that used Str2Num.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26