/[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 610 - (show annotations)
Fri Apr 4 13:56:59 2003 UTC (21 years, 11 months ago) by jonathan
Original Path: trunk/thuban/Thuban/Model/load.py
File MIME type: text/x-python
File size: 11198 byte(s)
Rename Color.None to Color.Transparent.

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 ProcessSession(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, directory):
78 """Inititialize the Sax handler.
79
80 The directory parameter should be the directory containing the
81 session file. It's needed to interpret embedded relative
82 filenames.
83 """
84 self.directory = directory
85 self.chars = ''
86 self.theSession = None
87 self.aMap = None
88 self.aLayer = None
89
90 def startElementNS(self, name, qname, attrs):
91 """Call the method given for name in self.start_dispatcher
92 """
93 if name[0] is None:
94 method_name = self.start_dispatcher.get(name[1])
95 else:
96 # Dispatch with namespace
97 method_name = self.start_dispatcher.get(name)
98 if method_name is not None:
99 getattr(self, method_name)(name, qname, attrs)
100
101 def endElementNS(self, name, qname):
102 """Call the method given for name in self.end_dispatcher
103 """
104 if name[0] is None:
105 method_name = self.end_dispatcher.get(name[1])
106 else:
107 # Dispatch with namespace
108 method_name = self.end_dispatcher.get(name)
109 if method_name is not None:
110 getattr(self, method_name)(name, qname)
111
112 def start_session(self, name, qname, attrs):
113 self.theSession = Session(attrs.get((None, 'title'), None))
114 start_dispatcher['session'] = "start_session"
115
116 def end_session(self, name, qname):
117 pass
118 end_dispatcher['session'] = "end_session"
119
120 def start_map(self, name, qname, attrs):
121 """Start a map."""
122 self.aMap = Map(attrs.get((None, 'title'), None))
123 start_dispatcher['map'] = "start_map"
124
125 def end_map(self, name, qname):
126 self.theSession.AddMap(self.aMap)
127 end_dispatcher['map'] = "end_map"
128
129 def start_projection(self, name, qname, attrs):
130 self.ProjectionParams = [ ]
131 start_dispatcher['projection'] = "start_projection"
132
133 def end_projection(self, name, qname):
134 self.aMap.SetProjection(Projection(self.ProjectionParams))
135 end_dispatcher['projection'] = "end_projection"
136
137 def start_parameter(self, name, qname, attrs):
138 s = attrs.get((None, 'value'))
139 s = str(s) # we can't handle unicode in proj
140 self.ProjectionParams.append(s)
141 start_dispatcher['parameter'] = "start_parameter"
142
143 def start_layer(self, name, qname, attrs, layer_class = Layer):
144 """Start a layer
145
146 Instantiate a layer of class layer_class from the attributes in
147 attrs which may be a dictionary as well as the normal SAX attrs
148 object and bind it to self.aLayer.
149 """
150 title = attrs.get((None, 'title'), "")
151 filename = attrs.get((None, 'filename'), "")
152 filename = os.path.join(self.directory, filename)
153 fill = parse_color(attrs.get((None, 'fill'), "None"))
154 stroke = parse_color(attrs.get((None, 'stroke'), "#000000"))
155 stroke_width = int(attrs.get((None, 'stroke_width'), "1"))
156 self.aLayer = layer_class(title, filename, fill = fill,
157 stroke = stroke, lineWidth = stroke_width)
158 start_dispatcher['layer'] = "start_layer"
159
160 def end_layer(self, name, qname):
161 self.aMap.AddLayer(self.aLayer)
162 end_dispatcher['layer'] = "end_layer"
163
164 def start_classification(self, name, qname, attrs):
165 field = attrs.get((None, 'field'), None)
166
167 fieldType = attrs.get((None, 'field_type'), None)
168 dbFieldType = self.aLayer.GetFieldType(field)
169
170 if fieldType != dbFieldType:
171 raise ValueError(_("xml field type differs from database!"))
172
173 # setup conversion routines depending on the kind of data
174 # we will be seeing later on
175 if fieldType == FIELDTYPE_STRING:
176 self.conv = str
177 elif fieldType == FIELDTYPE_INT:
178 self.conv = lambda p: int(float(p))
179 elif fieldType == FIELDTYPE_DOUBLE:
180 self.conv = float
181
182 self.aLayer.GetClassification().SetField(field)
183
184 start_dispatcher['classification'] = "start_classification"
185
186 def end_classification(self, name, qname):
187 pass
188 end_dispatcher['classification'] = "end_classification"
189
190 def start_clnull(self, name, qname, attrs):
191 self.cl_group = ClassGroupDefault()
192 self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
193 self.cl_prop = ClassGroupProperties()
194 start_dispatcher['clnull'] = "start_clnull"
195
196 def end_clnull(self, name, qname):
197 self.cl_group.SetProperties(self.cl_prop)
198 self.aLayer.GetClassification().SetDefaultGroup(self.cl_group)
199 del self.cl_group, self.cl_prop
200 end_dispatcher['clnull'] = "end_clnull"
201
202 def start_clpoint(self, name, qname, attrs):
203 attrib_value = attrs.get((None, 'value'), "0")
204
205 #try:
206 #value = Str2Num(attrib_value)
207 #except:
208 #value = attrib_value
209
210 value = self.conv(attrib_value)
211
212 self.cl_group = ClassGroupSingleton(value)
213 self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
214 self.cl_prop = ClassGroupProperties()
215
216 start_dispatcher['clpoint'] = "start_clpoint"
217
218 def end_clpoint(self, name, qname):
219 self.cl_group.SetProperties(self.cl_prop)
220 self.aLayer.GetClassification().AddGroup(self.cl_group)
221 del self.cl_group, self.cl_prop
222 end_dispatcher['clpoint'] = "end_clpoint"
223
224 def start_clrange(self, name, qname, attrs):
225
226 try:
227 min = self.conv(attrs.get((None, 'min'), "0"))
228 max = self.conv(attrs.get((None, 'max'), "0"))
229 #min = Str2Num(attrs.get((None, 'min'), "0"))
230 #max = Str2Num(attrs.get((None, 'max'), "0"))
231 except ValueError:
232 raise ValueError(_("Classification range is not a number!"))
233
234 self.cl_group = ClassGroupRange(min, max)
235 self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
236 self.cl_prop = ClassGroupProperties()
237
238 start_dispatcher['clrange'] = "start_clrange"
239
240 def end_clrange(self, name, qname):
241 self.cl_group.SetProperties(self.cl_prop)
242 self.aLayer.GetClassification().AddGroup(self.cl_group)
243 del self.cl_group, self.cl_prop
244 end_dispatcher['clrange'] = "end_clrange"
245
246 def start_cldata(self, name, qname, attrs):
247 self.cl_prop.SetLineColor(
248 parse_color(attrs.get((None, 'stroke'), "None")))
249 self.cl_prop.SetLineWidth(
250 int(attrs.get((None, 'stroke_width'), "0")))
251 self.cl_prop.SetFill(parse_color(attrs.get((None, 'fill'), "None")))
252 start_dispatcher['cldata'] = "start_cldata"
253
254 def end_cldata(self, name, qname):
255 pass
256 end_dispatcher['cldata'] = "end_cldata"
257
258 def start_table(self, name, qname, attrs):
259 #print "table title: %s" % attrs.get('title', None)
260 pass
261 start_dispatcher['table'] = "start_table"
262
263 def end_table(self, name, qname):
264 pass
265 end_dispatcher['table'] = "end_table"
266
267 def start_labellayer(self, name, qname, attrs):
268 self.aLayer = self.aMap.LabelLayer()
269 start_dispatcher['labellayer'] = "start_labellayer"
270
271 def start_label(self, name, qname, attrs):
272 x = float(attrs[(None, 'x')])
273 y = float(attrs[(None, 'y')])
274 text = attrs[(None, 'text')]
275 halign = attrs[(None, 'halign')]
276 valign = attrs[(None, 'valign')]
277 self.aLayer.AddLabel(x, y, text, halign = halign, valign = valign)
278 start_dispatcher['label'] = "start_label"
279
280 def characters(self, chars):
281 pass
282
283
284 def load_session(filename):
285 """Load a Thuban session from the file object file"""
286 dir = os.path.dirname(filename)
287 file = open(filename)
288 handler = ProcessSession(dir)
289
290 parser = make_parser()
291 parser.setContentHandler(handler)
292 parser.setErrorHandler(ErrorHandler())
293 parser.setFeature(xml.sax.handler.feature_namespaces, 1)
294
295 #
296 # Well, this isn't pretty, but it appears that if you
297 # use Python 2.2 without the site-package _xmlplus then
298 # the following will fail, and without them it will work.
299 # However, if you do have the site-package and you don't
300 # call these functions, the reader raises an exception
301 #
302 # The reason we set these to 0 in the first place is
303 # because there is an unresolved issue with external
304 # entities causing an exception in the reader
305 #
306 try:
307 parser.setFeature(xml.sax.handler.feature_validation, 0)
308 parser.setFeature(xml.sax.handler.feature_external_ges, 0)
309 parser.setFeature(xml.sax.handler.feature_external_pes, 0)
310 except SAXNotRecognizedException:
311 pass
312
313 parser.parse(file)
314
315 session = handler.theSession
316 # Newly loaded session aren't modified
317 session.UnsetModified()
318
319 return session
320

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26