/[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 694 - (show annotations)
Wed Apr 16 16:39: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: 11806 byte(s)
(XMLProcessor): New. Contains all the general XML reading methods that
        were part of ProcessSession.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26