Mercurial > fife-parpg
comparison engine/python/fife/extensions/serializers/simplexml.py @ 568:bfbf329e1da8
Forgot to add the simplexml.py file in my last commit.
author | prock@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Mon, 28 Jun 2010 18:43:03 +0000 |
parents | |
children | 466d76db9701 |
comparison
equal
deleted
inserted
replaced
567:9152ed2b5bb8 | 568:bfbf329e1da8 |
---|---|
1 # -*- coding: utf-8 -*- | |
2 | |
3 # #################################################################### | |
4 # Copyright (C) 2005-2010 by the FIFE team | |
5 # http://www.fifengine.net | |
6 # This file is part of FIFE. | |
7 # | |
8 # FIFE is free software; you can redistribute it and/or | |
9 # modify it under the terms of the GNU Lesser General Public | |
10 # License as published by the Free Software Foundation; either | |
11 # version 2.1 of the License, or (at your option) any later version. | |
12 # | |
13 # This library is distributed in the hope that it will be useful, | |
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 # Lesser General Public License for more details. | |
17 # | |
18 # You should have received a copy of the GNU Lesser General Public | |
19 # License along with this library; if not, write to the | |
20 # Free Software Foundation, Inc., | |
21 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 # #################################################################### | |
23 | |
24 import os | |
25 from StringIO import StringIO | |
26 | |
27 try: | |
28 import xml.etree.cElementTree as ET | |
29 except: | |
30 import xml.etree.ElementTree as ET | |
31 | |
32 | |
33 EMPTY_XML_FILE="""\ | |
34 <?xml version='1.0' encoding='UTF-8'?> | |
35 <Settings> | |
36 | |
37 </Settings> | |
38 """ | |
39 | |
40 class SimpleXMLSerializer(object): | |
41 """ | |
42 This class is a simple interface to get and store data in XML files. | |
43 | |
44 Usage:: | |
45 from fife.extensions.serializers.simplexml import SimpleXMLSerializer | |
46 serializer = SimpleXMLSerializer(filename="somefile.xml") | |
47 settings.set("module_name", "variable_name", "value") | |
48 somevariable = settings.get("module_name", "variable_name", "default_value") | |
49 """ | |
50 def __init__(self, filename=None): | |
51 self._file = filename | |
52 self._tree = None | |
53 self._root_element = None | |
54 | |
55 if self._file: | |
56 self.load(self._file) | |
57 | |
58 def load(self, filename=None): | |
59 """ | |
60 Loads the XML file into memory and validates it. | |
61 | |
62 @note: If the file does not exist it will automatically create a blank file for you. | |
63 """ | |
64 if filename: | |
65 self._file = filename | |
66 | |
67 if not self._file: | |
68 print "Cannot load file. No filename specified!" | |
69 return | |
70 | |
71 if not os.path.exists(self._file): | |
72 self._tree = ET.parse(StringIO(EMPTY_XML_FILE)) | |
73 self._tree.write(self._file, 'UTF-8') | |
74 else: | |
75 self._tree = ET.parse(self._file) | |
76 | |
77 self._root_element = self._tree.getroot() | |
78 self._validateTree() | |
79 | |
80 def save(self, filename=None): | |
81 """ | |
82 Saves the XML file. | |
83 | |
84 @note: This Overwrites the file if it exists. | |
85 """ | |
86 if filename: | |
87 savefile = filename | |
88 else: | |
89 savefile = self._file | |
90 | |
91 if not savefile: | |
92 print "Cannot save file. No filename specified!" | |
93 return | |
94 | |
95 """ Writes the settings to file """ | |
96 self._indent(self._root_element) | |
97 self._tree.write(savefile, 'UTF-8') | |
98 | |
99 | |
100 def get(self, module, name, defaultValue=None): | |
101 """ Gets the value of a specified variable | |
102 | |
103 @param module: Name of the module to get the variable from | |
104 @param name: Variable name | |
105 @param defaultValue: Specifies the default value to return if the variable is not found | |
106 @type defaultValue: C{str} or C{unicode} or C{int} or C{float} or C{bool} or C{list} or C{dict} | |
107 """ | |
108 if not isinstance(name, str) and not isinstance(name, unicode): | |
109 raise AttributeError("SimpleXMLSerializer.get(): Invalid type for name argument.") | |
110 | |
111 moduleTree = self._getModuleTree(module) | |
112 element = None | |
113 for e in moduleTree.getchildren(): | |
114 if e.tag == "Setting" and e.get("name", "") == name: | |
115 element = e | |
116 break | |
117 else: | |
118 return defaultValue | |
119 | |
120 e_value = element.text | |
121 e_strip = element.get("strip", "1").strip().lower() | |
122 e_type = str(element.get("type", "str")).strip() | |
123 | |
124 if e_value is None: | |
125 return defaultValue | |
126 | |
127 # Strip value | |
128 if e_strip == "" or e_strip == "false" or e_strip == "no" or e_strip == "0": | |
129 e_strip = False | |
130 else: e_strip = True | |
131 | |
132 if e_type == "str" or e_type == "unicode": | |
133 if e_strip: e_value = e_value.strip() | |
134 else: | |
135 e_value = e_value.strip() | |
136 | |
137 # Return value | |
138 if e_type == 'int': | |
139 return int(e_value) | |
140 elif e_type == 'float': | |
141 return float(e_value) | |
142 elif e_type == 'bool': | |
143 e_value = e_value.lower() | |
144 if e_value == "" or e_value == "false" or e_value == "no" or e_value == "0": | |
145 return False | |
146 else: | |
147 return True | |
148 elif e_type == 'str': | |
149 return str(e_value) | |
150 elif e_type == 'unicode': | |
151 return unicode(e_value) | |
152 elif e_type == 'list': | |
153 return self._deserializeList(e_value) | |
154 elif e_type == 'dict': | |
155 return self._deserializeDict(e_value) | |
156 | |
157 def set(self, module, name, value, extra_attrs={}): | |
158 """ | |
159 Sets a variable to specified value. | |
160 | |
161 @param module: Module where the variable should be set | |
162 @param name: Name of the variable | |
163 @param value: Value to assign to the variable | |
164 @type value: C{str} or C{unicode} or C{int} or C{float} or C{bool} or C{list} or C{dict} | |
165 @param extra_attrs: Extra attributes to be stored in the XML-file | |
166 @type extra_attrs: C{dict} | |
167 """ | |
168 if not isinstance(name, str) and not isinstance(name, unicode): | |
169 raise AttributeError("Settings:set: Invalid type for name argument.") | |
170 | |
171 moduleTree = self._getModuleTree(module) | |
172 e_type = "str" | |
173 | |
174 if isinstance(value, bool): # This must be before int | |
175 e_type = "bool" | |
176 value = str(value) | |
177 elif isinstance(value, int): | |
178 e_type = "int" | |
179 value = str(value) | |
180 elif isinstance(value, float): | |
181 e_type = "float" | |
182 value = str(value) | |
183 elif isinstance(value, unicode): | |
184 e_type = "unicode" | |
185 value = unicode(value) | |
186 elif isinstance(value, list): | |
187 e_type = "list" | |
188 value = self._serializeList(value) | |
189 elif isinstance(value, dict): | |
190 e_type = "dict" | |
191 value = self._serializeDict(value) | |
192 else: | |
193 e_type = "str" | |
194 value = str(value) | |
195 | |
196 for e in moduleTree.getchildren(): | |
197 if e.tag != "Setting": continue | |
198 if e.get("name", "") == name: | |
199 e.text = value | |
200 break | |
201 else: | |
202 attrs = {"name":name, "type":e_type} | |
203 for k in extra_attrs: | |
204 if k not in attrs: | |
205 attrs[k] = extra_args[k] | |
206 elm = ET.SubElement(moduleTree, "Setting", attrs) | |
207 elm.text = value | |
208 | |
209 def _validateTree(self): | |
210 """ Iterates the XML tree and prints warning when an invalid tag is found """ | |
211 for c in self._root_element.getchildren(): | |
212 if c.tag != "Module": | |
213 print "Invalid tag in " + self._file + ". Expected Module, got: ", c.tag | |
214 elif c.get("name", "") == "": | |
215 print "Invalid tag in " + self._file + ". Module name is empty." | |
216 else: | |
217 for e in c.getchildren(): | |
218 if e.tag != "Setting": | |
219 print "Invalid tag in " + self._file + " in module: ",c.tag, | |
220 print ". Expected Setting, got: ", e.tag | |
221 elif c.get("name", "") == "": | |
222 print "Invalid tag in " + self._file + " in module: ",c.tag, | |
223 print ". Setting name is empty", e.tag | |
224 | |
225 def _getModuleTree(self, module): | |
226 """ | |
227 Returns a module element from the XML tree. If no module with the specified | |
228 name exists, a new element will be created. | |
229 | |
230 @param module: The module to get from the settings tree | |
231 @type module: C{string} | |
232 """ | |
233 if not isinstance(module, str) and not isinstance(module, unicode): | |
234 raise AttributeError("Settings:_getModuleTree: Invalid type for module argument.") | |
235 | |
236 for c in self._root_element.getchildren(): | |
237 if c.tag == "Module" and c.get("name", "") == module: | |
238 return c | |
239 | |
240 # Create module | |
241 return ET.SubElement(self._root_element, "Module", {"name":module}) | |
242 | |
243 def _indent(self, elem, level=0): | |
244 """ | |
245 Adds whitespace, so the resulting XML-file is properly indented. | |
246 Shamelessly stolen from http://effbot.org/zone/element-lib.htm | |
247 """ | |
248 i = "\n" + level*" " | |
249 if len(elem): | |
250 if not elem.text or not elem.text.strip(): | |
251 elem.text = i + " " | |
252 if not elem.tail or not elem.tail.strip(): | |
253 elem.tail = i | |
254 for elem in elem: | |
255 self._indent(elem, level+1) | |
256 if not elem.tail or not elem.tail.strip(): | |
257 elem.tail = i | |
258 else: | |
259 if level and (not elem.tail or not elem.tail.strip()): | |
260 elem.tail = i | |
261 | |
262 # FIXME: | |
263 # These serialization functions are not reliable at all | |
264 # This will only serialize the first level of a dict or list | |
265 # It will not check the types nor the content for conflicts. | |
266 # Perhaps we should add a small serialization library? | |
267 def _serializeList(self, list): | |
268 """ Serializes a list, so it can be stored in a text file """ | |
269 return " ; ".join(list) | |
270 | |
271 def _deserializeList(self, string): | |
272 """ Deserializes a list back into a list object """ | |
273 return string.split(" ; ") | |
274 | |
275 def _serializeDict(self, dict): | |
276 """ Serializes a list, so it can be stored in a text file """ | |
277 serial = "" | |
278 for key in dict: | |
279 value = dict[key] | |
280 if serial != "": serial += " ; " | |
281 serial += str(key)+" : "+str(value) | |
282 | |
283 return serial | |
284 | |
285 def _deserializeDict(self, serial): | |
286 """ Deserializes a list back into a dict object """ | |
287 dict = {} | |
288 items = serial.split(" ; ") | |
289 for i in items: | |
290 kv_pair = i.split(" : ") | |
291 dict[kv_pair[0]] = kv_pair[1] | |
292 return dict | |
293 |