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

Contents of /branches/WIP-pyshapelib-bramz/Thuban/Model/save.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 697 - (show annotations)
Wed Apr 16 16:40:07 2003 UTC (21 years, 10 months ago) by jonathan
Original Path: trunk/thuban/Thuban/Model/save.py
File MIME type: text/x-python
File size: 11127 byte(s)
(XMLSaver): New. Contains all the general XML writing methods that were
        part of SessionSaver.
(SessionSaver): Renamed from Saver.

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 Thuban for details.
9
10 """
11 Functions to save a session to a file
12 """
13
14 __version__ = "$Revision$"
15
16 # fix for people using python2.1
17 from __future__ import nested_scopes
18
19 import os
20 import string
21
22 import Thuban.Lib.fileutil
23
24 from Thuban.Model.color import Color
25
26 from Thuban.Model.classification import *
27
28 #
29 # one level of indention
30 #
31 TAB = " "
32
33 def relative_filename(dir, filename):
34 """Return a filename relative to dir for the absolute file name absname.
35
36 This is almost the same as the function in fileutil, except that dir
37 can be an empty string in which case filename will be returned
38 unchanged.
39 """
40 if dir:
41 return Thuban.Lib.fileutil.relative_filename(dir, filename)
42 else:
43 return filename
44
45 def escape(data):
46 """Escape &, \", ', <, and > in a string of data.
47 """
48 data = string.replace(data, "&", "&amp;")
49 data = string.replace(data, "<", "&lt;")
50 data = string.replace(data, ">", "&gt;")
51 data = string.replace(data, '"', "&quot;")
52 data = string.replace(data, "'", "&apos;")
53 return data
54
55 class XMLSaver:
56 """Abstract XMLSaver.
57
58 Should be overridden to provide specific object saving functionality.
59 """
60
61 def __init__(self):
62 self.filename = None
63 pass
64
65 def write(self, file_or_filename):
66 """Write the session to a file.
67
68 The argument may be either a file object or a filename. If it's
69 a filename, the file will be opened for writing. Files of
70 shapefiles will be stored as filenames relative to the directory
71 the file is stored in (as given by os.path.dirname(filename)) if
72 they have a common parent directory other than the root
73 directory.
74
75 If the argument is a file object (which is determined by the
76 presence of a write method) all filenames will be absolute
77 filenames.
78 """
79
80 # keep track of how many levels of indentation to write
81 self.indent_level = 0
82 # track whether an element is currently open. see open_element().
83 self.element_open = 0
84
85 if hasattr(file_or_filename, "write"):
86 # it's a file object
87 self.file = file_or_filename
88 self.dir = ""
89 else:
90 self.filename = file_or_filename
91 self.dir = os.path.dirname(self.filename)
92 self.file = open(self.filename, 'w')
93
94 def close(self):
95 assert self.indent_level == 0
96 if self.filename is not None:
97 self.file.close()
98
99 def write_header(self, doctype, system):
100 """Write the XML header"""
101 self.file.write('<?xml version="1.0" encoding="UTF-8"?>\n')
102 self.file.write('<!DOCTYPE %s SYSTEM "%s">\n' % (doctype, system))
103
104 def open_element(self, element, attrs = {}):
105
106 #
107 # we note when an element is opened so that if two open_element()
108 # calls are made successively we can end the currently open
109 # tag and will later write a proper close tag. otherwise,
110 # if a close_element() call is made directly after an open_element()
111 # call we will close the tag with a />
112 #
113 if self.element_open == 1:
114 self.file.write(">\n")
115
116 self.element_open = 1
117
118 # Helper function to write an element open tag with attributes
119 self.file.write("%s<%s" % (TAB*self.indent_level, element))
120 self.__write_attribs(attrs)
121
122 self.indent_level += 1
123
124 def close_element(self, element):
125 self.indent_level -= 1
126 assert self.indent_level >= 0
127
128 # see open_element() for an explanation
129 if self.element_open == 1:
130 self.element_open = 0
131 self.file.write("/>\n")
132 else:
133 self.file.write("%s</%s>\n" % (TAB*self.indent_level, element))
134
135 def write_element(self, element, attrs = {}):
136 """write an element that won't need a closing tag"""
137 self.open_element(element, attrs)
138 self.close_element(element)
139
140 def __write_attribs(self, attrs):
141 for name, value in attrs.items():
142 self.file.write(' %s="%s"' % (escape(name), escape(value)))
143
144 class SessionSaver(XMLSaver):
145
146 """Class to serialize a session into an XML file.
147
148 Applications built on top of Thuban may derive from this class and
149 override or extend the methods to save additional information. This
150 additional information should take the form of additional attributes
151 or elements whose names are prefixed with a namespace. To define a
152 namespace derived classes should extend the write_session method to
153 pass the namespaces to the default implementation.
154 """
155
156
157 def __init__(self, session):
158 XMLSaver.__init__(self)
159 self.session = session
160
161 def write(self, file_or_filename):
162 XMLSaver.write(self, file_or_filename)
163
164 self.write_header("session", "thuban.dtd")
165 self.write_session(self.session)
166 self.close()
167
168 def write_session(self, session, attrs = None, namespaces = ()):
169 """Write the session and its contents
170
171 By default, write a session element with the title attribute and
172 call write_map for each map contained in the session.
173
174 The optional argument attrs is for additional attributes and, if
175 given, should be a mapping from attribute names to attribute
176 values. The values should not be XML-escaped yet.
177
178 The optional argument namespaces, if given, should be a sequence
179 of (name, URI) pairs. The namespaces are written as namespace
180 attributes into the session element. This is mainly useful for
181 derived classes that need to store additional information in a
182 thuban session file.
183 """
184 if attrs is None:
185 attrs = {}
186 attrs["title"] = session.title
187 for name, uri in namespaces:
188 attrs["xmlns:" + name] = uri
189 self.open_element("session", attrs)
190 for map in session.Maps():
191 self.write_map(map)
192 self.close_element("session")
193
194 def write_map(self, map):
195 """Write the map and its contents.
196
197 By default, write a map element element with the title
198 attribute, call write_projection to write the projection
199 element, call write_layer for each layer contained in the map
200 and finally call write_label_layer to write the label layer.
201 """
202 self.open_element('map title="%s"' % escape(map.title))
203 self.write_projection(map.projection)
204 for layer in map.Layers():
205 self.write_layer(layer)
206 self.write_label_layer(map.LabelLayer())
207 self.close_element('map')
208
209 def write_projection(self, projection):
210 """Write the projection.
211 """
212 if projection and len(projection.params) > 0:
213 self.open_element("projection")
214 for param in projection.params:
215 self.write_element('parameter value="%s"' % escape(param))
216 self.close_element("projection")
217
218 def write_layer(self, layer, attrs = None):
219 """Write the layer.
220
221 The optional argument attrs is for additional attributes and, if
222 given, should be a mapping from attribute names to attribute
223 values. The values should not be XML-escaped yet.
224 """
225 lc = layer.GetClassification()
226
227 if attrs is None:
228 attrs = {}
229
230 attrs["title"] = layer.title
231 attrs["filename"] = relative_filename(self.dir, layer.filename)
232 attrs["stroke"] = lc.GetDefaultLineColor().hex()
233 attrs["stroke_width"] = str(lc.GetDefaultLineWidth())
234 attrs["fill"] = lc.GetDefaultFill().hex()
235
236 self.open_element("layer", attrs)
237 self.write_classification(layer)
238 self.close_element("layer")
239
240 def write_classification(self, layer, attrs = None):
241 if attrs is None:
242 attrs = {}
243
244 lc = layer.GetClassification()
245
246 field = lc.GetField()
247
248 #
249 # there isn't a classification of anything
250 # so don't do anything
251 #
252 if field is None: return
253
254 attrs["field"] = field
255 attrs["field_type"] = str(lc.GetFieldType())
256 self.open_element("classification", attrs)
257
258
259 types = [[lambda p: 'clnull label="%s"' % p.GetLabel(),
260 lambda p: 'clnull'],
261 [lambda p: 'clpoint label="%s" value="%s"' %
262 (p.GetLabel(), str(p.GetValue())),
263 lambda p: 'clpoint'],
264 [lambda p: 'clrange label="%s" min="%s" max="%s"' %
265 (p.GetLabel(),
266 str(p.GetMin()), (str(p.GetMax()))),
267 lambda p: 'clrange']]
268
269 def write_class_group(group):
270 type = -1
271 if isinstance(group, ClassGroupDefault): type = 0
272 elif isinstance(group, ClassGroupSingleton): type = 1
273 elif isinstance(group, ClassGroupRange): type = 2
274 elif isinstance(group, ClassGroupMap): type = 3
275 assert type >= 0
276
277 if type <= 2:
278 data = group.GetProperties()
279 dict = {'stroke' : data.GetLineColor().hex(),
280 'stroke_width': str(data.GetLineWidth()),
281 'fill' : data.GetFill().hex()}
282
283 self.open_element(types[type][0](group))
284 self.write_element("cldata", dict)
285 self.close_element(types[type][1](group))
286 else: pass # XXX: we need to handle maps
287
288 for i in lc:
289 write_class_group(i)
290
291 self.close_element("classification")
292
293 def write_label_layer(self, layer):
294 """Write the label layer.
295 """
296 labels = layer.Labels()
297 if labels:
298 self.open_element('labellayer')
299 for label in labels:
300 self.write_element(('label x="%g" y="%g" text="%s"'
301 ' halign="%s" valign="%s"')
302 % (label.x, label.y, label.text, label.halign,
303 label.valign))
304 self.close_element('labellayer')
305
306
307
308 def save_session(session, file, saver_class = None):
309 """Save the session session to a file.
310
311 The file argument may either be a filename or an open file object.
312
313 The optional argument saver_class is the class to use to serialize
314 the session. By default or if it's None, the saver class will be
315 SessionSaver.
316
317 If writing the session is successful call the session's
318 UnsetModified method
319 """
320 if saver_class is None:
321 saver_class = SessionSaver
322 saver = saver_class(session)
323 saver.write(file)
324
325 # after a successful save consider the session unmodified.
326 session.UnsetModified()

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26