/[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 706 - (show annotations)
Wed Apr 23 08:44:21 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: 12328 byte(s)
(XMLReader): Renamed from XMLProcessor to
        promote symmetry. There now exists XMLReader and XMLWriter.
(XMLReader.read): New. Call to read the given file descriptor or
        filename.
(XMLReader.close): New. Make sure the file is closed.
(XMLReader.GetFileName): New. Return just the file name that is being read from.
(XMLReader.GetDirectory): New. Return just the directory of the file
        that is being read.
(XMLReader.AddDispatchers): New. Take a dictionary which contains
        the names of functions to call as the XML tree is parsed.
(XMLReader.startElementNS): Updated to use new dispatcher dictionary.
(XMLReader.endElementNS): Updated to use new dispatcher dictionary.
(SessionLoader): Removed class variables start_dispatcher and
        end_dispatcher since this functionality is now part of a class
        instance. Fixes RTbug #1808.
(SessionLoader.__init__): Add dispatcher functions.
(load_xmlfile): Code was moved into the XMLReader.read().
(load_session): Use modified SessionLoader.

1 # Copyright (C) 2001, 2002 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 sys, 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, "write"):
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 self.__dispatchers.update(dict)
137
138 #for key, (start, end) in dict.iteritems():
139 #if start is not None: self.start_dispatcher[key] = start
140 #if end is not None: self.end_dispatcher[key] = end
141
142 def startElementNS(self, name, qname, attrs):
143 """Call the method given for name in self.start_dispatcher
144 """
145 if name[0] is None:
146 method_name = self.__dispatchers.get(name[1])
147 #method_name = self.start_dispatcher.get(name[1])
148 else:
149 # Dispatch with namespace
150 method_name = self.__dispatchers.get(name)
151 if method_name is not None \
152 and method_name[0] is not None:
153 getattr(self, method_name[0])(name, qname, attrs)
154
155 def endElementNS(self, name, qname):
156 """Call the method given for name in self.end_dispatcher
157 """
158 if name[0] is None:
159 method_name = self.__dispatchers.get(name[1])
160 #method_name = self.end_dispatcher.get(name[1])
161 else:
162 # Dispatch with namespace
163 method_name = self.__dispatchers.get(name)
164 if method_name is not None \
165 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
203 def end_map(self, name, qname):
204 self.theSession.AddMap(self.aMap)
205
206 def start_projection(self, name, qname, attrs):
207 self.ProjectionParams = [ ]
208
209 def end_projection(self, name, qname):
210 self.aMap.SetProjection(Projection(self.ProjectionParams))
211
212 def start_parameter(self, name, qname, attrs):
213 s = attrs.get((None, 'value'))
214 s = str(s) # we can't handle unicode in proj
215 self.ProjectionParams.append(s)
216
217 def start_layer(self, name, qname, attrs, layer_class = Layer):
218 """Start a layer
219
220 Instantiate a layer of class layer_class from the attributes in
221 attrs which may be a dictionary as well as the normal SAX attrs
222 object and bind it to self.aLayer.
223 """
224 title = attrs.get((None, 'title'), "")
225 filename = attrs.get((None, 'filename'), "")
226 filename = os.path.join(self.GetDirectory(), filename)
227 fill = parse_color(attrs.get((None, 'fill'), "None"))
228 stroke = parse_color(attrs.get((None, 'stroke'), "#000000"))
229 stroke_width = int(attrs.get((None, 'stroke_width'), "1"))
230 self.aLayer = layer_class(title, filename, fill = fill,
231 stroke = stroke, lineWidth = stroke_width)
232
233 def end_layer(self, name, qname):
234 self.aMap.AddLayer(self.aLayer)
235
236 def start_classification(self, name, qname, attrs):
237 field = attrs.get((None, 'field'), None)
238
239 fieldType = attrs.get((None, 'field_type'), None)
240 dbFieldType = self.aLayer.GetFieldType(field)
241
242 if fieldType != dbFieldType:
243 raise ValueError(_("xml field type differs from database!"))
244
245 # setup conversion routines depending on the kind of data
246 # we will be seeing later on
247 if fieldType == FIELDTYPE_STRING:
248 self.conv = str
249 elif fieldType == FIELDTYPE_INT:
250 self.conv = lambda p: int(float(p))
251 elif fieldType == FIELDTYPE_DOUBLE:
252 self.conv = float
253
254 self.aLayer.GetClassification().SetField(field)
255
256
257 def end_classification(self, name, qname):
258 pass
259
260 def start_clnull(self, name, qname, attrs):
261 self.cl_group = ClassGroupDefault()
262 self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
263 self.cl_prop = ClassGroupProperties()
264
265 def end_clnull(self, name, qname):
266 self.cl_group.SetProperties(self.cl_prop)
267 self.aLayer.GetClassification().SetDefaultGroup(self.cl_group)
268 del self.cl_group, self.cl_prop
269
270 def start_clpoint(self, name, qname, attrs):
271 attrib_value = attrs.get((None, 'value'), "0")
272
273 #try:
274 #value = Str2Num(attrib_value)
275 #except:
276 #value = attrib_value
277
278 value = self.conv(attrib_value)
279
280 self.cl_group = ClassGroupSingleton(value)
281 self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
282 self.cl_prop = ClassGroupProperties()
283
284
285 def end_clpoint(self, name, qname):
286 self.cl_group.SetProperties(self.cl_prop)
287 self.aLayer.GetClassification().AppendGroup(self.cl_group)
288 del self.cl_group, self.cl_prop
289
290 def start_clrange(self, name, qname, attrs):
291
292 try:
293 min = self.conv(attrs.get((None, 'min'), "0"))
294 max = self.conv(attrs.get((None, 'max'), "0"))
295 #min = Str2Num(attrs.get((None, 'min'), "0"))
296 #max = Str2Num(attrs.get((None, 'max'), "0"))
297 except ValueError:
298 raise ValueError(_("Classification range is not a number!"))
299
300 self.cl_group = ClassGroupRange(min, max)
301 self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
302 self.cl_prop = ClassGroupProperties()
303
304
305 def end_clrange(self, name, qname):
306 self.cl_group.SetProperties(self.cl_prop)
307 self.aLayer.GetClassification().AppendGroup(self.cl_group)
308 del self.cl_group, self.cl_prop
309
310 def start_cldata(self, name, qname, attrs):
311 self.cl_prop.SetLineColor(
312 parse_color(attrs.get((None, 'stroke'), "None")))
313 self.cl_prop.SetLineWidth(
314 int(attrs.get((None, 'stroke_width'), "0")))
315 self.cl_prop.SetFill(parse_color(attrs.get((None, 'fill'), "None")))
316
317 def end_cldata(self, name, qname):
318 pass
319
320 def start_table(self, name, qname, attrs):
321 #print "table title: %s" % attrs.get('title', None)
322 pass
323
324 def end_table(self, name, qname):
325 pass
326
327 def start_labellayer(self, name, qname, attrs):
328 self.aLayer = self.aMap.LabelLayer()
329
330 def start_label(self, name, qname, attrs):
331 x = float(attrs[(None, 'x')])
332 y = float(attrs[(None, 'y')])
333 text = attrs[(None, 'text')]
334 halign = attrs[(None, 'halign')]
335 valign = attrs[(None, 'valign')]
336 self.aLayer.AddLabel(x, y, text, halign = halign, valign = valign)
337
338 def characters(self, chars):
339 pass
340
341
342 def load_session(filename):
343 """Load a Thuban session from the file object file"""
344
345 handler = SessionLoader()
346 handler.read(filename)
347
348 session = handler.theSession
349 # Newly loaded session aren't modified
350 session.UnsetModified()
351
352 return session
353

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26