Package lib :: Module xml
[hide private]
[frames] | no frames]

Source Code for Module lib.xml

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2008-2009,2012,2014 Edward d'Auvergne                         # 
  4  #                                                                             # 
  5  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  6  #                                                                             # 
  7  # This program is free software: you can redistribute it and/or modify        # 
  8  # it under the terms of the GNU General Public License as published by        # 
  9  # the Free Software Foundation, either version 3 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # This program is distributed in the hope that it will be useful,             # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 15  # GNU General Public License for more details.                                # 
 16  #                                                                             # 
 17  # You should have received a copy of the GNU General Public License           # 
 18  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 19  #                                                                             # 
 20  ############################################################################### 
 21   
 22  # Module docstring. 
 23  """Module containing generic functions for creation and parsing of XML representations of Python objects.""" 
 24   
 25  # Python module imports (note that some of these are needed for the eval() function call). 
 26  import numpy 
 27  from numpy import set_printoptions, array, int16, int32, float32, float64, inf, ndarray, zeros 
 28  from re import search 
 29   
 30  # Modify numpy for better output of numbers and structures. 
 31  set_printoptions(precision=15, threshold=inf) 
 32   
 33  # relax module imports. 
 34  import lib.arg_check 
 35  import lib.check_types 
 36  from lib.compat import unicode 
 37  from lib.float import floatAsByteArray, packBytesAsPyFloat 
 38  from lib.errors import RelaxError 
 39   
 40   
41 -def fill_object_contents(doc, elem, object=None, blacklist=[]):
42 """Place all simple python objects into the XML element namespace. 43 44 @param doc: The XML document object. 45 @type doc: xml.dom.minidom.Document instance 46 @param elem: The element to add all python objects to. 47 @type elem: XML element object 48 @keyword object: The python class instance containing the objects to add. 49 @type object: instance 50 @keyword blacklist: A list of object names to exclude. 51 @type blacklist: list of str 52 """ 53 54 # Loop over the elements of the object. 55 for name in dir(object): 56 # Skip blacklisted objects. 57 if name in blacklist: 58 continue 59 60 # Skip special objects. 61 if search("^_", name): 62 continue 63 64 # Only pack objects in the __mod_attr__ list, if that list exists. 65 if hasattr(object, '_mod_attr') and name not in object._mod_attr: 66 continue 67 68 # Create a new element for this object, and add it to the main element. 69 sub_elem = doc.createElement(name) 70 elem.appendChild(sub_elem) 71 72 # Get the sub-object. 73 subobj = getattr(object, name) 74 75 # Convert to XML. 76 object_to_xml(doc, sub_elem, value=subobj)
77 78
79 -def node_value_to_python(elem):
80 """Convert the node value to a python expression. 81 82 @param elem: The XML element. 83 @type elem: xml.dom.minidom.Element instance 84 """ 85 86 # Remove whitespace. 87 val = elem.nodeValue.strip() 88 89 # Convert to python and return. 90 return eval(val)
91 92
93 -def object_to_xml(doc, elem, value=None):
94 """Convert the given value into an XML form. 95 96 @param doc: The XML document object. 97 @type doc: xml.dom.minidom.Document instance 98 @param elem: The element to add the Python objects to. 99 @type elem: XML element object 100 @keyword value: The Python object to convert. 101 @type value: anything 102 """ 103 104 # Add the text value to the sub element. 105 val_elem = doc.createElement('value') 106 elem.appendChild(val_elem) 107 val_elem.appendChild(doc.createTextNode(repr(value))) 108 109 # The object type. 110 if value is None: 111 py_type = 'None' 112 elif isinstance(value, bool): 113 py_type = 'bool' 114 elif isinstance(value, str) or isinstance(value, unicode): 115 py_type = 'str' 116 elif isinstance(value, float): 117 py_type = 'float' 118 elif isinstance(value, int): 119 py_type = 'int' 120 elif isinstance(value, list): 121 py_type = 'list' 122 elif isinstance(value, dict): 123 py_type = 'dict' 124 elif isinstance(value, ndarray): 125 py_type = repr(value.dtype) 126 else: 127 raise RelaxError("Unknown type for the value %s." % repr(value)) 128 129 # Store as an attribute. 130 elem.setAttribute('type', py_type) 131 132 # Store floats as IEEE-754 byte arrays (for full precision storage). 133 if lib.check_types.is_float(value): 134 val_elem = doc.createElement('ieee_754_byte_array') 135 elem.appendChild(val_elem) 136 val_elem.appendChild(doc.createTextNode(repr(floatAsByteArray(value)))) 137 138 # Store lists with floats as IEEE-754 byte arrays. 139 elif (isinstance(value, list) or isinstance(value, ndarray)) and len(value) and lib.check_types.is_float(value[0]): 140 # The converted list. 141 ieee_obj = [] 142 conv = False 143 for i in range(len(value)): 144 # A float. 145 if lib.check_types.is_float(value[i]): 146 ieee_obj.append(floatAsByteArray(value[i])) 147 conv = True 148 149 # All other data. 150 else: 151 ieee_obj.append(value) 152 153 # Store as XML. 154 if conv: 155 # The element. 156 val_elem = doc.createElement('ieee_754_byte_array') 157 elem.appendChild(val_elem) 158 159 # Add the text. 160 val_elem.appendChild(doc.createTextNode(repr(ieee_obj))) 161 162 # Store dictionaries with floats as IEEE-754 byte arrays. 163 elif py_type == 'dict': 164 # The converted dict. 165 ieee_obj = {} 166 conv = False 167 for key in value: 168 if lib.check_types.is_float(value[key]): 169 ieee_obj[key] = floatAsByteArray(value[key]) 170 conv = True 171 172 # Store as XML. 173 if conv: 174 # The element. 175 val_elem = doc.createElement('ieee_754_byte_array') 176 elem.appendChild(val_elem) 177 178 # Add the text. 179 val_elem.appendChild(doc.createTextNode(repr(ieee_obj))) 180 181 # Store matrices of floats as IEEE-754 byte arrays. 182 elif lib.arg_check.is_float_matrix(value, none_elements=True, raise_error=False): 183 # The converted list. 184 ieee_obj = [] 185 for i in range(len(value)): 186 # Handle None elements. 187 if value[i] is None: 188 ieee_obj.append(None) 189 continue 190 191 # A normal float list or numpy array. 192 ieee_obj.append([]) 193 for j in range(len(value[i])): 194 ieee_obj[-1].append(floatAsByteArray(value[i][j])) 195 196 # The element. 197 val_elem = doc.createElement('ieee_754_byte_array') 198 elem.appendChild(val_elem) 199 200 # Add the text. 201 val_elem.appendChild(doc.createTextNode(repr(ieee_obj)))
202 203
204 -def xml_to_object(elem, base_object=None, set_fn=None, file_version=1, blacklist=[]):
205 """Convert the XML elements into python objects, and place these into the base object. 206 207 @param elem: The element to extract all python objects from. 208 @type elem: xml.dom.minidom.Element instance 209 @keyword base_object: The python class instance to place the objects into. 210 @type base_object: instance 211 @keyword set_fn: A function used to replace setattr for placing the object into the base 212 object. 213 @type set_fn: function 214 @keyword file_version: The relax XML version of the XML file. 215 @type file_version: int 216 @keyword blacklist: A list of object names to exclude. 217 @type blacklist: list of str 218 """ 219 220 # Loop over the nodes of the element 221 for node in elem.childNodes: 222 # Skip empty nodes. 223 if node.localName == None: 224 continue 225 226 # The name of the python object to recreate. 227 name = str(node.localName) 228 229 # Skip blacklisted objects. 230 if name in blacklist: 231 continue 232 233 # The value - original file version. 234 if file_version == 1: 235 # IEEE-754 floats (for full precision restoration). 236 ieee_array = node.getAttribute('ieee_754_byte_array') 237 if ieee_array: 238 value = packBytesAsPyFloat(eval(ieee_array)) 239 240 # Get the node contents. 241 else: 242 value = node_value_to_python(node.childNodes[0]) 243 244 # The value - second file version. 245 elif file_version == 2: 246 # Get the type. 247 py_type = node.getAttribute('type') 248 if not search('dtype', py_type): 249 py_type = eval(py_type) 250 251 # Loop over the info nodes of the Python object. 252 ieee_value = None 253 for sub_node in node.childNodes: 254 # Get the value. 255 if sub_node.localName == 'value': 256 value = node_value_to_python(sub_node.childNodes[0]) 257 258 # IEEE-754 floats (for full precision restoration). 259 if sub_node.localName == 'ieee_754_byte_array': 260 ieee_value = node_value_to_python(sub_node.childNodes[0]) 261 262 # Use IEEE-754 floats when possible. 263 if ieee_value: 264 # Simple float. 265 if py_type == float: 266 value = packBytesAsPyFloat(ieee_value) 267 268 # Convert dictionaries. 269 elif py_type == dict: 270 for key in ieee_value: 271 value[key] = packBytesAsPyFloat(ieee_value[key]) 272 273 # Convert lists. 274 elif py_type == list: 275 # Loop over the first dimension. 276 for i in range(len(value)): 277 # List of lists. 278 if isinstance(value[i], list) or isinstance(value[i], ndarray): 279 for j in range(len(value[i])): 280 value[i][j] = packBytesAsPyFloat(ieee_value[i][j]) 281 282 # None values. 283 elif ieee_value[i] == None: 284 value[i] = None 285 286 # Normal list. 287 else: 288 value[i] = packBytesAsPyFloat(ieee_value[i]) 289 290 # Numpy types. 291 elif search('dtype', py_type): 292 # The specific type. 293 numpy_type = getattr(numpy, py_type[7:-2]) 294 295 # Build a new array of the correct type. 296 value = zeros(value.shape, numpy_type) 297 298 # A matrix. 299 if isinstance(value[0], ndarray): 300 for i in range(len(value)): 301 for j in range(len(value[i])): 302 value[i, j] = packBytesAsPyFloat(ieee_value[i][j]) 303 304 # A vector. 305 else: 306 for i in range(len(value)): 307 value[i] = packBytesAsPyFloat(ieee_value[i]) 308 309 # Set the value. 310 setattr(base_object, name, value)
311