Package data :: Module relax_xml
[hide private]
[frames] | no frames]

Source Code for Module data.relax_xml

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2008-2012 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 fns for creation and parsing of XML representations of python objects.""" 
 24   
 25  # Python module imports. 
 26  import numpy 
 27  from numpy import set_printoptions, array, float32, float64, inf, nan, ndarray, zeros 
 28  try: 
 29      from numpy import float16 
 30  except ImportError: 
 31      float16 = float32    # Support for old numpy versions. 
 32  try: 
 33      from numpy import float128 
 34  except ImportError: 
 35      float128 = float64    # Support for 32-bit numpy versions. 
 36  from re import search 
 37   
 38  # Modify numpy for better output of numbers and structures. 
 39  set_printoptions(precision=15, threshold=nan) 
 40   
 41  # relax module imports. 
 42  import arg_check 
 43  from float import floatAsByteArray, packBytesAsPyFloat 
 44  from relax_errors import RelaxError 
 45   
 46   
47 -def fill_object_contents(doc, elem, object=None, blacklist=[]):
48 """Place all simple python objects into the XML element namespace. 49 50 @param doc: The XML document object. 51 @type doc: xml.dom.minidom.Document instance 52 @param elem: The element to add all python objects to. 53 @type elem: XML element object 54 @keyword object: The python class instance containing the objects to add. 55 @type object: instance 56 @keyword blacklist: A list of object names to exclude. 57 @type blacklist: list of str 58 """ 59 60 # Loop over the elements of the object. 61 for name in dir(object): 62 # Skip blacklisted objects. 63 if name in blacklist: 64 continue 65 66 # Skip special objects. 67 if search("^_", name): 68 continue 69 70 # Only pack objects in the __mod_attr__ list, if that list exists. 71 if hasattr(object, '_mod_attr') and name not in object._mod_attr: 72 continue 73 74 # Create a new element for this object, and add it to the main element. 75 sub_elem = doc.createElement(name) 76 elem.appendChild(sub_elem) 77 78 # Get the sub-object. 79 subobj = getattr(object, name) 80 81 # Convert to XML. 82 object_to_xml(doc, sub_elem, value=subobj)
83 84
85 -def node_value_to_python(elem):
86 """Convert the node value to a python expression. 87 88 @param elem: The XML element. 89 @type elem: xml.dom.minidom.Element instance 90 """ 91 92 # Remove whitespace. 93 val = elem.nodeValue.strip() 94 95 # Convert to python and return. 96 return eval(val)
97 98
99 -def object_to_xml(doc, elem, value=None):
100 """Convert the given value into an XML form. 101 102 @param doc: The XML document object. 103 @type doc: xml.dom.minidom.Document instance 104 @param elem: The element to add the Python objects to. 105 @type elem: XML element object 106 @keyword value: The Python object to convert. 107 @type value: anything 108 """ 109 110 # Add the text value to the sub element. 111 val_elem = doc.createElement('value') 112 elem.appendChild(val_elem) 113 val_elem.appendChild(doc.createTextNode(repr(value))) 114 115 # The object type. 116 if value == None: 117 py_type = 'None' 118 elif isinstance(value, bool): 119 py_type = 'bool' 120 elif isinstance(value, str): 121 py_type = 'str' 122 elif isinstance(value, float): 123 py_type = 'float' 124 elif isinstance(value, int): 125 py_type = 'int' 126 elif isinstance(value, list): 127 py_type = 'list' 128 elif isinstance(value, dict): 129 py_type = 'dict' 130 elif isinstance(value, ndarray): 131 py_type = repr(value.dtype) 132 else: 133 raise RelaxError("Unknown type for the value '%s'." % value) 134 135 # Store as an attribute. 136 elem.setAttribute('type', py_type) 137 138 # Store floats as IEEE-754 byte arrays (for full precision storage). 139 if arg_check.check_float(value): 140 val_elem = doc.createElement('ieee_754_byte_array') 141 elem.appendChild(val_elem) 142 val_elem.appendChild(doc.createTextNode(repr(floatAsByteArray(value)))) 143 144 # Store lists with floats as IEEE-754 byte arrays. 145 elif (isinstance(value, list) or isinstance(value, ndarray)) and len(value) and arg_check.check_float(value[0]): 146 # The converted list. 147 ieee_obj = [] 148 conv = False 149 for i in range(len(value)): 150 # A float. 151 if arg_check.check_float(value[i]): 152 ieee_obj.append(floatAsByteArray(value[i])) 153 conv = True 154 155 # All other data. 156 else: 157 ieee_obj.append(value) 158 159 # Store as XML. 160 if conv: 161 # The element. 162 val_elem = doc.createElement('ieee_754_byte_array') 163 elem.appendChild(val_elem) 164 165 # Add the text. 166 val_elem.appendChild(doc.createTextNode(repr(ieee_obj))) 167 168 # Store dictionaries with floats as IEEE-754 byte arrays. 169 elif py_type == 'dict': 170 # The converted dict. 171 ieee_obj = {} 172 conv = False 173 for key in list(value.keys()): 174 if arg_check.check_float(value[key]): 175 ieee_obj[key] = floatAsByteArray(value[key]) 176 conv = True 177 178 # Store as XML. 179 if conv: 180 # The element. 181 val_elem = doc.createElement('ieee_754_byte_array') 182 elem.appendChild(val_elem) 183 184 # Add the text. 185 val_elem.appendChild(doc.createTextNode(repr(ieee_obj))) 186 187 # Store matrices of floats as IEEE-754 byte arrays. 188 elif arg_check.is_float_matrix(value, raise_error=False): 189 # The converted list. 190 ieee_obj = [] 191 for i in range(len(value)): 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 # Normal list. 283 else: 284 value[i] = packBytesAsPyFloat(ieee_value[i]) 285 286 # Numpy types. 287 elif search('dtype', py_type): 288 # The specific type. 289 numpy_type = getattr(numpy, py_type[7:-2]) 290 291 # Build a new array of the correct type. 292 value = zeros(value.shape, numpy_type) 293 294 # A matrix. 295 if isinstance(value[0], ndarray): 296 for i in range(len(value)): 297 for j in range(len(value[i])): 298 value[i, j] = packBytesAsPyFloat(ieee_value[i][j]) 299 300 # A vector. 301 else: 302 for i in range(len(value)): 303 value[i] = packBytesAsPyFloat(ieee_value[i]) 304 305 # Set the value. 306 setattr(base_object, name, value)
307