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