/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/Model/load.py
ViewVC logotype

Annotation of /branches/WIP-pyshapelib-bramz/Thuban/Model/load.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 784 - (hide 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 bh 723 # Copyright (C) 2001, 2002, 2003 by Intevation GmbH
2 bh 6 # Authors:
3     # Jan-Oliver Wagner <[email protected]>
4 bh 267 # Bernhard Herzog <[email protected]>
5 jonathan 413 # Jonathan Coles <[email protected]>
6 bh 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 bh 723 import string, os
17 bh 267
18     import xml.sax
19     import xml.sax.handler
20 jonathan 526 from xml.sax import make_parser, ErrorHandler, SAXNotRecognizedException
21 bh 267
22 jan 374 from Thuban import _
23 jonathan 413
24 jonathan 473 from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
25     FIELDTYPE_STRING
26    
27 bh 6 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 jonathan 413 from Thuban.Model.classification import Classification, \
33 jonathan 439 ClassGroupDefault, ClassGroupSingleton, ClassGroupRange, ClassGroupMap, \
34     ClassGroupProperties
35 bh 6
36    
37 bh 267 def parse_color(color):
38     """Return the color object for the string color.
39 bh 6
40 bh 267 Color may be either 'None' or of the form '#RRGGBB' in the usual
41     HTML color notation
42 bh 6 """
43     color = string.strip(color)
44     if color == "None":
45 jonathan 610 result = Color.Transparent
46 bh 6 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 jan 374 raise ValueError(_("Invalid hexadecimal color specification %s")
54 bh 6 % color)
55     else:
56 jan 374 raise ValueError(_("Invalid color specification %s") % color)
57 bh 6 return result
58    
59    
60 jonathan 706 class XMLReader(xml.sax.handler.ContentHandler):
61 bh 6
62 bh 267 # Dictionary mapping element names (or (URI, element name) pairs for
63 jonathan 365 # documents using namespaces) to method names. The methods should
64 bh 267 # 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 jonathan 706 def __init__(self):
77 bh 6 self.chars = ''
78 jonathan 706 self.__directory = ""
79     self.__dispatchers = {}
80 bh 6
81 jonathan 706 def read(self, file_or_filename):
82    
83 jonathan 722 if hasattr(file_or_filename, "read"):
84 jonathan 706 # 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 bh 763 parser = make_parser()
93     parser.setContentHandler(self)
94     parser.setErrorHandler(ErrorHandler())
95     parser.setFeature(xml.sax.handler.feature_namespaces, 1)
96 jonathan 706
97 bh 763 #
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 jonathan 706
115 bh 763 parser.parse(self.__file)
116 jonathan 706
117     self.close()
118    
119     def close(self):
120     self.__file.close()
121    
122 jonathan 737 def GetFilename(self):
123 jonathan 706 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 jonathan 722 """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 jonathan 706 self.__dispatchers.update(dict)
144    
145 bh 267 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 jonathan 706 method_name = self.__dispatchers.get(name[1])
150 bh 267 else:
151     # Dispatch with namespace
152 jonathan 706 method_name = self.__dispatchers.get(name)
153 jonathan 722 if method_name is not None and method_name[0] is not None:
154 jonathan 706 getattr(self, method_name[0])(name, qname, attrs)
155 bh 6
156 bh 267 def endElementNS(self, name, qname):
157     """Call the method given for name in self.end_dispatcher
158     """
159     if name[0] is None:
160 jonathan 706 method_name = self.__dispatchers.get(name[1])
161 bh 267 else:
162     # Dispatch with namespace
163 jonathan 706 method_name = self.__dispatchers.get(name)
164 jonathan 722 if method_name is not None and method_name[1] is not None:
165 jonathan 706 getattr(self, method_name[1])(name, qname)
166 bh 6
167 jonathan 706 class SessionLoader(XMLReader):
168 jonathan 694
169 jonathan 706 def __init__(self):
170 jonathan 694 """Inititialize the Sax handler."""
171 jonathan 706 XMLReader.__init__(self)
172 jonathan 694
173     self.theSession = None
174     self.aMap = None
175     self.aLayer = None
176    
177 jonathan 706 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 bh 267 def start_session(self, name, qname, attrs):
193     self.theSession = Session(attrs.get((None, 'title'), None))
194 bh 6
195 bh 267 def end_session(self, name, qname):
196     pass
197 bh 6
198 bh 267 def start_map(self, name, qname, attrs):
199     """Start a map."""
200     self.aMap = Map(attrs.get((None, 'title'), None))
201 jonathan 737 self.__projReceiver = self.aMap
202 bh 267
203     def end_map(self, name, qname):
204     self.theSession.AddMap(self.aMap)
205 jonathan 737 self.__projReceiver = None
206 bh 267
207     def start_projection(self, name, qname, attrs):
208 jonathan 744 self.ProjectionName = attrs.get((None, 'name'), None)
209 bh 267 self.ProjectionParams = [ ]
210    
211     def end_projection(self, name, qname):
212 jonathan 744 self.__projReceiver.SetProjection(
213     Projection(self.ProjectionParams, self.ProjectionName))
214 bh 267
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 jonathan 694 filename = os.path.join(self.GetDirectory(), filename)
230 jonathan 772 visible = attrs.get((None, 'visible'), "true")
231 bh 267 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 bh 723 self.aLayer = layer_class(title,
235     self.theSession.OpenShapefile(filename),
236     fill = fill, stroke = stroke,
237 jonathan 772 lineWidth = stroke_width,
238     visible = visible != "false")
239 bh 267
240 jonathan 737 self.__projReceiver = self.aLayer
241    
242 bh 267 def end_layer(self, name, qname):
243     self.aMap.AddLayer(self.aLayer)
244 jonathan 737 self.__projReceiver = None
245 bh 267
246 jonathan 365 def start_classification(self, name, qname, attrs):
247 jonathan 465 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 jonathan 365
267     def end_classification(self, name, qname):
268     pass
269    
270     def start_clnull(self, name, qname, attrs):
271 jonathan 439 self.cl_group = ClassGroupDefault()
272     self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
273     self.cl_prop = ClassGroupProperties()
274 jonathan 365
275     def end_clnull(self, name, qname):
276 jonathan 439 self.cl_group.SetProperties(self.cl_prop)
277     self.aLayer.GetClassification().SetDefaultGroup(self.cl_group)
278     del self.cl_group, self.cl_prop
279 jonathan 365
280     def start_clpoint(self, name, qname, attrs):
281     attrib_value = attrs.get((None, 'value'), "0")
282    
283 jonathan 465 value = self.conv(attrib_value)
284    
285 jonathan 439 self.cl_group = ClassGroupSingleton(value)
286     self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
287     self.cl_prop = ClassGroupProperties()
288 jonathan 413
289 jonathan 365
290     def end_clpoint(self, name, qname):
291 jonathan 439 self.cl_group.SetProperties(self.cl_prop)
292 jonathan 614 self.aLayer.GetClassification().AppendGroup(self.cl_group)
293 jonathan 439 del self.cl_group, self.cl_prop
294 jonathan 365
295     def start_clrange(self, name, qname, attrs):
296    
297     try:
298 jonathan 465 min = self.conv(attrs.get((None, 'min'), "0"))
299     max = self.conv(attrs.get((None, 'max'), "0"))
300 jonathan 365 except ValueError:
301 jan 374 raise ValueError(_("Classification range is not a number!"))
302 jonathan 365
303 jonathan 439 self.cl_group = ClassGroupRange(min, max)
304     self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
305     self.cl_prop = ClassGroupProperties()
306 jonathan 413
307 jonathan 365
308     def end_clrange(self, name, qname):
309 jonathan 439 self.cl_group.SetProperties(self.cl_prop)
310 jonathan 614 self.aLayer.GetClassification().AppendGroup(self.cl_group)
311 jonathan 439 del self.cl_group, self.cl_prop
312 jonathan 365
313     def start_cldata(self, name, qname, attrs):
314 jonathan 465 self.cl_prop.SetLineColor(
315     parse_color(attrs.get((None, 'stroke'), "None")))
316     self.cl_prop.SetLineWidth(
317 jonathan 390 int(attrs.get((None, 'stroke_width'), "0")))
318 jonathan 439 self.cl_prop.SetFill(parse_color(attrs.get((None, 'fill'), "None")))
319 jonathan 365
320     def end_cldata(self, name, qname):
321     pass
322    
323 bh 267 def start_table(self, name, qname, attrs):
324 jonathan 493 #print "table title: %s" % attrs.get('title', None)
325     pass
326 bh 267
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 jonathan 694 def load_session(filename):
346     """Load a Thuban session from the file object file"""
347    
348 jonathan 706 handler = SessionLoader()
349     handler.read(filename)
350 jonathan 694
351 bh 6 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