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

Source Code for Module lib.xml

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2008-2013 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, inf, nan, ndarray, zeros 
 28  from re import search 
 29   
 30  # Modify numpy for better output of numbers and structures. 
 31  set_printoptions(precision=15, threshold=nan) 
 32   
 33  # relax module imports. 
 34  import lib.arg_check 
 35  import lib.check_types 
 36  from lib.float import floatAsByteArray, packBytesAsPyFloat 
 37  from lib.errors import RelaxError 
 38   
 39   
40 -def fill_object_contents(doc, elem, object=None, blacklist=[]):
41 """Place all simple python objects into the XML element namespace. 42 43 @param doc: The XML document object. 44 @type doc: xml.dom.minidom.Document instance 45 @param elem: The element to add all python objects to. 46 @type elem: XML element object 47 @keyword object: The python class instance containing the objects to add. 48 @type object: instance 49 @keyword blacklist: A list of object names to exclude. 50 @type blacklist: list of str 51 """ 52 53 # Loop over the elements of the object. 54 for name in dir(object): 55 # Skip blacklisted objects. 56 if name in blacklist: 57 continue 58 59 # Skip special objects. 60 if search("^_", name): 61 continue 62 63 # Only pack objects in the __mod_attr__ list, if that list exists. 64 if hasattr(object, '_mod_attr') and name not in object._mod_attr: 65 continue 66 67 # Create a new element for this object, and add it to the main element. 68 sub_elem = doc.createElement(name) 69 elem.appendChild(sub_elem) 70 71 # Get the sub-object. 72 subobj = getattr(object, name) 73 74 # Convert to XML. 75 object_to_xml(doc, sub_elem, value=subobj)
76 77
78 -def node_value_to_python(elem):
79 """Convert the node value to a python expression. 80 81 @param elem: The XML element. 82 @type elem: xml.dom.minidom.Element instance 83 """ 84 85 # Remove whitespace. 86 val = elem.nodeValue.strip() 87 88 # Convert to python and return. 89 return eval(val)
90 91
92 -def object_to_xml(doc, elem, value=None):
93 """Convert the given value into an XML form. 94 95 @param doc: The XML document object. 96 @type doc: xml.dom.minidom.Document instance 97 @param elem: The element to add the Python objects to. 98 @type elem: XML element object 99 @keyword value: The Python object to convert. 100 @type value: anything 101 """ 102 103 # Add the text value to the sub element. 104 val_elem = doc.createElement('value') 105 elem.appendChild(val_elem) 106 val_elem.appendChild(doc.createTextNode(repr(value))) 107 108 # The object type. 109 if value == None: 110 py_type = 'None' 111 elif isinstance(value, bool): 112 py_type = 'bool' 113 elif isinstance(value, str): 114 py_type = 'str' 115 elif isinstance(value, float): 116 py_type = 'float' 117 elif isinstance(value, int): 118 py_type = 'int' 119 elif isinstance(value, list): 120 py_type = 'list' 121 elif isinstance(value, dict): 122 py_type = 'dict' 123 elif isinstance(value, ndarray): 124 py_type = repr(value.dtype) 125 else: 126 raise RelaxError("Unknown type for the value '%s'." % value) 127 128 # Store as an attribute. 129 elem.setAttribute('type', py_type) 130 131 # Store floats as IEEE-754 byte arrays (for full precision storage). 132 if lib.check_types.is_float(value): 133 val_elem = doc.createElement('ieee_754_byte_array') 134 elem.appendChild(val_elem) 135 val_elem.appendChild(doc.createTextNode(repr(floatAsByteArray(value)))) 136 137 # Store lists with floats as IEEE-754 byte arrays. 138 elif (isinstance(value, list) or isinstance(value, ndarray)) and len(value) and lib.check_types.is_float(value[0]): 139 # The converted list. 140 ieee_obj = [] 141 conv = False 142 for i in range(len(value)): 143 # A float. 144 if lib.check_types.is_float(value[i]): 145 ieee_obj.append(floatAsByteArray(value[i])) 146 conv = True 147 148 # All other data. 149 else: 150 ieee_obj.append(value) 151 152 # Store as XML. 153 if conv: 154 # The element. 155 val_elem = doc.createElement('ieee_754_byte_array') 156 elem.appendChild(val_elem) 157 158 # Add the text. 159 val_elem.appendChild(doc.createTextNode(repr(ieee_obj))) 160 161 # Store dictionaries with floats as IEEE-754 byte arrays. 162 elif py_type == 'dict': 163 # The converted dict. 164 ieee_obj = {} 165 conv = False 166 for key in list(value.keys()): 167 if lib.check_types.is_float(value[key]): 168 ieee_obj[key] = floatAsByteArray(value[key]) 169 conv = True 170 171 # Store as XML. 172 if conv: 173 # The element. 174 val_elem = doc.createElement('ieee_754_byte_array') 175 elem.appendChild(val_elem) 176 177 # Add the text. 178 val_elem.appendChild(doc.createTextNode(repr(ieee_obj))) 179 180 # Store matrices of floats as IEEE-754 byte arrays. 181 elif lib.arg_check.is_float_matrix(value, raise_error=False): 182 # The converted list. 183 ieee_obj = [] 184 for i in range(len(value)): 185 ieee_obj.append([]) 186 for j in range(len(value[i])): 187 ieee_obj[-1].append(floatAsByteArray(value[i][j])) 188 189 # The element. 190 val_elem = doc.createElement('ieee_754_byte_array') 191 elem.appendChild(val_elem) 192 193 # Add the text. 194 val_elem.appendChild(doc.createTextNode(repr(ieee_obj)))
195 196
197 -def xml_to_object(elem, base_object=None, set_fn=None, file_version=1, blacklist=[]):
198 """Convert the XML elements into python objects, and place these into the base object. 199 200 @param elem: The element to extract all python objects from. 201 @type elem: xml.dom.minidom.Element instance 202 @keyword base_object: The python class instance to place the objects into. 203 @type base_object: instance 204 @keyword set_fn: A function used to replace setattr for placing the object into the base 205 object. 206 @type set_fn: function 207 @keyword file_version: The relax XML version of the XML file. 208 @type file_version: int 209 @keyword blacklist: A list of object names to exclude. 210 @type blacklist: list of str 211 """ 212 213 # Loop over the nodes of the element 214 for node in elem.childNodes: 215 # Skip empty nodes. 216 if node.localName == None: 217 continue 218 219 # The name of the python object to recreate. 220 name = str(node.localName) 221 222 # Skip blacklisted objects. 223 if name in blacklist: 224 continue 225 226 # The value - original file version. 227 if file_version == 1: 228 # IEEE-754 floats (for full precision restoration). 229 ieee_array = node.getAttribute('ieee_754_byte_array') 230 if ieee_array: 231 value = packBytesAsPyFloat(eval(ieee_array)) 232 233 # Get the node contents. 234 else: 235 value = node_value_to_python(node.childNodes[0]) 236 237 # The value - second file version. 238 elif file_version == 2: 239 # Get the type. 240 py_type = node.getAttribute('type') 241 if not search('dtype', py_type): 242 py_type = eval(py_type) 243 244 # Loop over the info nodes of the Python object. 245 ieee_value = None 246 for sub_node in node.childNodes: 247 # Get the value. 248 if sub_node.localName == 'value': 249 value = node_value_to_python(sub_node.childNodes[0]) 250 251 # IEEE-754 floats (for full precision restoration). 252 if sub_node.localName == 'ieee_754_byte_array': 253 ieee_value = node_value_to_python(sub_node.childNodes[0]) 254 255 # Use IEEE-754 floats when possible. 256 if ieee_value: 257 # Simple float. 258 if py_type == float: 259 value = packBytesAsPyFloat(ieee_value) 260 261 # Convert dictionaries. 262 elif py_type == dict: 263 for key in ieee_value: 264 value[key] = packBytesAsPyFloat(ieee_value[key]) 265 266 # Convert lists. 267 elif py_type == list: 268 # Loop over the first dimension. 269 for i in range(len(value)): 270 # List of lists. 271 if isinstance(value[i], list) or isinstance(value[i], ndarray): 272 for j in range(len(value[i])): 273 value[i][j] = packBytesAsPyFloat(ieee_value[i][j]) 274 275 # Normal list. 276 else: 277 value[i] = packBytesAsPyFloat(ieee_value[i]) 278 279 # Numpy types. 280 elif search('dtype', py_type): 281 # The specific type. 282 numpy_type = getattr(numpy, py_type[7:-2]) 283 284 # Build a new array of the correct type. 285 value = zeros(value.shape, numpy_type) 286 287 # A matrix. 288 if isinstance(value[0], ndarray): 289 for i in range(len(value)): 290 for j in range(len(value[i])): 291 value[i, j] = packBytesAsPyFloat(ieee_value[i][j]) 292 293 # A vector. 294 else: 295 for i in range(len(value)): 296 value[i] = packBytesAsPyFloat(ieee_value[i]) 297 298 # Set the value. 299 setattr(base_object, name, value)
300