Changeset 786685e in sasview for src/sans/dataloader
- Timestamp:
- May 15, 2014 5:08:38 PM (10 years ago)
- Branches:
- master, ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc, costrafo411, magnetic_scatt, release-4.1.1, release-4.1.2, release-4.2.2, release_4.0.1, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1243, ticket-1249, ticket885, unittest-saveload
- Children:
- 4a0dc427
- Parents:
- 4e9f227 (diff), bb1b892 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent. - Location:
- src/sans/dataloader/readers
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sans/dataloader/readers/cansas_constants.py
r9e2bc6c rac5b69d 3 3 the cansas_reader.py file to read in any version of the cansas format. 4 4 """ 5 class cansasConstants: 6 7 ns = '' 5 class CansasConstants: 6 """ 7 The base class to define where all of the data is to be saved by 8 cansas_reader.py. 9 """ 10 11 names = '' 8 12 format = '' 9 13 10 14 11 15 def __init__(self): 12 self.n s = self.CANSAS_NS16 self.names = self.CANSAS_NS 13 17 self.format = self.CANSAS_FORMAT 14 18 15 19 16 def _iterate_namespace(self, namespace):20 def iterate_namespace(self, namespace): 17 21 """ 18 22 Method to iterate through a cansas constants tree based on a list of … … 23 27 """ 24 28 # The current level to look through in cansas_constants. 25 return_me = currentLevel()29 return_me = CurrentLevel() 26 30 return_me.current_level = self.CANSAS_FORMAT.get("SASentry") 27 31 # Defaults for variable and datatype … … 30 34 return_me.ns_optional = True 31 35 for name in namespace: 32 if name != "SASentry": 33 return_me.current_level = \ 34 return_me.current_level.get("children").get(name, "") 35 if return_me.current_level == "": 36 try: 37 if name != "SASentry": 36 38 return_me.current_level = \ 37 return_me.current_level.get("<any>", "") 38 cl_variable = return_me.current_level.get("variable", "") 39 cl_datatype = return_me.current_level.get("storeas", "") 40 cl_units_optional = \ 41 return_me.current_level.get("units_required", "") 42 # Where are how to store the variable for the given namespace 43 # CANSAS_CONSTANTS tree is hierarchical, so is no value, inherit 44 return_me.ns_variable = cl_variable if cl_variable != "" else \ 45 return_me.ns_variable 46 return_me.ns_datatype = cl_datatype if cl_datatype != "" else \ 47 return_me.ns_datatype 48 return_me.ns_optional = cl_units_optional if \ 49 cl_units_optional != return_me.ns_optional \ 50 else return_me.ns_optional 39 return_me.current_level.get("children").get(name, "") 40 if return_me.current_level == "": 41 return_me.current_level = \ 42 return_me.current_level.get("<any>", "") 43 cl_variable = return_me.current_level.get("variable", "") 44 cl_datatype = return_me.current_level.get("storeas", "") 45 cl_units_optional = \ 46 return_me.current_level.get("units_required", "") 47 # Where are how to store the variable for the given namespace 48 # CANSAS_CONSTANTS tree is hierarchical, so is no value, inherit 49 return_me.ns_variable = cl_variable if cl_variable != "" else \ 50 return_me.ns_variable 51 return_me.ns_datatype = cl_datatype if cl_datatype != "" else \ 52 return_me.ns_datatype 53 return_me.ns_optional = cl_units_optional if \ 54 cl_units_optional != return_me.ns_optional \ 55 else return_me.ns_optional 56 except AttributeError: 57 return_me.ns_variable = "{0}.meta_data[\"{2}\"] = \"{1}\"" 58 return_me.ns_datatype = "content" 59 return_me.ns_optional = True 51 60 return return_me 52 61 … … 454 463 } 455 464 SASINSTR_SRC = { 456 "attributes" : {"name" : {"variable" : "{0}.source.name = \"{1}\""}}, 465 "attributes" : {"name" : {"variable" : \ 466 "{0}.source.name = \"{1}\""}}, 457 467 "variable" : None, 458 468 "children" : { 459 "radiation" : {"variable" : "{0}.source.radiation = \"{1}\""}, 469 "radiation" : {"variable" : \ 470 "{0}.source.radiation = \"{1}\""}, 460 471 "beam_size" : SASINSTR_SRC_BEAMSIZE, 461 472 "beam_shape" : {"variable" : \ … … 647 658 "unit" : "pixel_size_unit", 648 659 "attributes" : { 649 "unit" : "{0}.pixel_size_unit = \"{1}\"", 660 "unit" : \ 661 "{0}.pixel_size_unit = \"{1}\"", 650 662 "storeas" : "content" 651 663 } … … 655 667 "unit" : "pixel_size_unit", 656 668 "attributes" : { 657 "unit" : "{0}.pixel_size_unit = \"{1}\"", 669 "unit" : \ 670 "{0}.pixel_size_unit = \"{1}\"", 658 671 "storeas" : "content" 659 672 } … … 663 676 "unit" : "pixel_size_unit", 664 677 "attributes" : { 665 "unit" : "{0}.pixel_size_unit = \"{1}\"", 678 "unit" : \ 679 "{0}.pixel_size_unit = \"{1}\"", 666 680 "storeas" : "content" 667 681 } … … 740 754 } 741 755 742 class currentLevel: 756 class CurrentLevel: 757 """ 758 A helper class to hold information on where you are in the constants tree 759 """ 743 760 744 761 current_level = '' … … 748 765 749 766 def __init__(self): 750 self.current_level = ''767 self.current_level = {} 751 768 self.ns_variable = '' 752 769 self.ns_datatype = "content" -
src/sans/dataloader/readers/cansas_reader.py
r2e3b055 rbb1b892 18 18 import sys 19 19 import datetime 20 import inspect 21 # For saving individual sections of data 20 22 from sans.dataloader.data_info import Data1D 21 23 from sans.dataloader.data_info import Collimation … … 24 26 from sans.dataloader.data_info import Process 25 27 from sans.dataloader.data_info import Aperture 28 # Both imports used. Do not remove either. 29 from xml.dom.minidom import parseString 26 30 import sans.dataloader.readers.xml_reader as xml_reader 27 from sans.dataloader.readers.cansas_constants import cansasConstants 31 from sans.dataloader.readers.xml_reader import XMLreader 32 from sans.dataloader.readers.cansas_constants import CansasConstants 28 33 29 34 _ZERO = 1e-16 … … 36 41 HAS_CONVERTER = False 37 42 38 constants = cansasConstants()39 CANSAS_FORMAT = constants.format40 CANSAS_NS = constants.ns43 CONSTANTS = CansasConstants() 44 CANSAS_FORMAT = CONSTANTS.format 45 CANSAS_NS = CONSTANTS.names 41 46 ALLOW_ALL = True 42 47 43 48 49 # minidom used in functions called by outside classes 50 import xml.dom.minidom 51 # DO NOT REMOVE 52 # Called by outside packages: 53 # sans.perspectives.invariant.invariant_state 54 # sans.perspectives.fitting.pagestate 44 55 def get_content(location, node): 45 56 """ … … 51 62 :return: Element, or None 52 63 """ 53 nodes = node.xpath(location, namespaces={'ns': CANSAS_NS}) 64 nodes = node.xpath(location, 65 namespaces={'ns': CANSAS_NS.get("1.0").get("ns")}) 54 66 55 67 if len(nodes) > 0: … … 59 71 60 72 61 def get_float(location, node): 62 """ 63 Get the content of a node as a float 64 65 :param location: xpath location 66 :param node: node to start at 67 """ 68 nodes = node.xpath(location, namespaces={'ns': CANSAS_NS}) 69 70 value = None 71 attr = {} 72 if len(nodes) > 0: 73 try: 74 value = float(nodes[0].text) 75 except: 76 # Could not pass, skip and return None 77 msg = "cansas_reader.get_float: could not " 78 msg += " convert '%s' to float" % nodes[0].text 79 logging.error(msg) 80 if nodes[0].get('unit') is not None: 81 attr['unit'] = nodes[0].get('unit') 82 return value, attr 83 84 85 # This is called by sans.perspectives.fitting.pagestate.py 86 # Do not remove 73 # DO NOT REMOVE 74 # Called by outside packages: 75 # sans.perspectives.fitting.pagestate 87 76 def write_node(doc, parent, name, value, attr={}): 88 77 """ … … 105 94 106 95 107 class Reader( ):96 class Reader(XMLreader): 108 97 """ 109 98 Class to load cansas 1D XML files … … 114 103 ##CanSAS version - defaults to version 1.0 115 104 cansas_version = "1.0" 116 ##Data reader 117 # TODO: make the reader extend the XMLreader class? 118 reader = xml_reader.XMLreader() 105 106 logging = [] 119 107 errors = [] 120 108 121 109 type_name = "canSAS" 122 123 110 ## Wildcards 124 type = ["XML files (*.xml)|*.xml" ]111 type = ["XML files (*.xml)|*.xml", "SasView Save Files (*.svs)|*.svs"] 125 112 ## List of allowed extensions 126 ext = ['.xml', '.XML' ]113 ext = ['.xml', '.XML', '.svs', '.SVS'] 127 114 128 115 ## Flag to bypass extension check … … 133 120 self.errors = [] 134 121 135 def is_cansas(self ):122 def is_cansas(self, ext="xml"): 136 123 """ 137 124 Checks to see if the xml file is a CanSAS file 138 125 """ 139 if self. reader.validateXML():126 if self.validate_xml(): 140 127 name = "{http://www.w3.org/2001/XMLSchema-instance}schemaLocation" 141 value = self. reader.xmlroot.get(name)142 if (CANSAS_NS.get(self.cansas_version).get("ns") == \143 value.rsplit(" ")[0] ):128 value = self.xmlroot.get(name) 129 if CANSAS_NS.get(self.cansas_version).get("ns") == \ 130 value.rsplit(" ")[0]: 144 131 return True 132 if ext == "svs": 133 return True 145 134 return False 146 135 … … 152 141 """ 153 142 # X - Q value; Y - Intensity (Abs) 154 x = numpy.empty(0)155 y = numpy.empty(0)156 dx = numpy.empty(0)157 dy = numpy.empty(0)143 x_vals = numpy.empty(0) 144 y_vals = numpy.empty(0) 145 dx_vals = numpy.empty(0) 146 dy_vals = numpy.empty(0) 158 147 dxl = numpy.empty(0) 159 148 dxw = numpy.empty(0) … … 162 151 output = [] 163 152 # ns - Namespace hierarchy for current xml object 164 ns = []153 ns_list = [] 165 154 166 155 # Check that the file exists … … 168 157 basename = os.path.basename(xml) 169 158 _, extension = os.path.splitext(basename) 170 # If the fi eltype is not allowed, return nothing159 # If the file type is not allowed, return nothing 171 160 if extension in self.ext or self.allow_all: 161 # Get the file location of 172 162 base_name = xml_reader.__file__ 173 163 base_name = base_name.replace("\\","/") … … 175 165 176 166 # Load in xml file and get the cansas version from the header 177 self. reader.setXMLFile(xml)178 root = self. reader.xmlroot167 self.set_xml_file(xml) 168 root = self.xmlroot 179 169 if root is None: 180 170 root = {} … … 187 177 188 178 # Link a schema to the XML file. 189 self. reader.setSchema(schema_path)179 self.set_schema(schema_path) 190 180 191 181 # Try to load the file, but raise an error if unable to. 192 182 # Check the file matches the XML schema 193 183 try: 194 if self.is_cansas( ):184 if self.is_cansas(extension): 195 185 # Get each SASentry from XML file and add it to a list. 196 186 entry_list = root.xpath('/ns:SASroot/ns:SASentry', 197 187 namespaces={'ns': cansas_defaults.get("ns")}) 198 ns .append("SASentry")188 ns_list.append("SASentry") 199 189 200 190 # If multiple files, modify the name for each is unique … … 204 194 # Parse each SASentry item 205 195 for entry in entry_list: 206 # Define a new Data1D object with zeroes for x and y 207 data1d = Data1D(x,y,dx,dy) 196 # Define a new Data1D object with zeroes for 197 # x_vals and y_vals 198 data1d = Data1D(x_vals, y_vals, dx_vals, dy_vals) 208 199 data1d.dxl = dxl 209 200 data1d.dxw = dxw … … 220 211 221 212 # Get all preprocessing events and encoding 222 self. reader.setProcessingInstructions()213 self.set_processing_instructions() 223 214 data1d.meta_data[PREPROCESS] = \ 224 self. reader.processingInstructions215 self.processing_instructions 225 216 226 217 # Parse the XML file 227 218 return_value, extras = \ 228 self._parse_entry(entry, ns , data1d)219 self._parse_entry(entry, ns_list, data1d) 229 220 del extras[:] 230 221 … … 251 242 output.append(return_value) 252 243 else: 253 value = self. reader.findInvalidXML()244 value = self.find_invalid_xml() 254 245 output.append("Invalid XML at: {0}".format(value)) 255 246 except: 256 247 # If the file does not match the schema, raise this error 257 raise RuntimeError, "%s cannot be read \increment" % xml248 raise RuntimeError, "%s cannot be read" % xml 258 249 return output 259 250 # Return a list of parsed entries that dataloader can manage 260 251 return None 261 252 262 def _create_unique_key(self, dictionary, name, i= 0):253 def _create_unique_key(self, dictionary, name, numb = 0): 263 254 """ 264 255 Create a unique key value for any dictionary to prevent overwriting … … 267 258 :param dictionary: A dictionary with any number of entries 268 259 :param name: The index of the item to be added to dictionary 269 :param i: The number to be appended to the name, starts at 0260 :param numb: The number to be appended to the name, starts at 0 270 261 """ 271 262 if dictionary.get(name) is not None: 272 i+= 1263 numb += 1 273 264 name = name.split("_")[0] 274 name += "_{0}".format( i)275 name = self._create_unique_key(dictionary, name, i)265 name += "_{0}".format(numb) 266 name = self._create_unique_key(dictionary, name, numb) 276 267 return name 277 268 … … 284 275 285 276 :param new_current_level: cansas_constants level as returned by 286 _iterate_namespace277 iterate_namespace 287 278 :param attr: The attributes of the node 288 279 :param data1d: Where the values will be saved … … 318 309 return 319 310 except: 320 err_msg = "CanSAS reader: could not convert the units" 311 err_msg = \ 312 "CanSAS reader: could not convert the units" 321 313 self.errors.append(err_msg) 322 314 return … … 343 335 return node_value, value_unit 344 336 345 def _parse_entry(self, dom, n s, data1d, extras =[]):337 def _parse_entry(self, dom, names=["SASentry"], data1d=None, extras=[]): 346 338 """ 347 339 Parse a SASEntry - new recursive method for parsing the dom of … … 349 341 and extra nodes to be read in simultaneously. 350 342 351 :param dom: dom object with a namespace base of n s352 :param n s: A list of element names that lead up to the dom object343 :param dom: dom object with a namespace base of names 344 :param names: A list of element names that lead up to the dom object 353 345 :param data1d: The data1d object that will be modified 354 346 :param extras: Any values that should go into meta_data when data1d 355 347 is not a Data1D object 356 348 """ 357 349 358 350 # A portion of every namespace entry 351 if data1d == None: 352 x_vals = numpy.empty(0) 353 y_vals = numpy.empty(0) 354 dx_vals = numpy.empty(0) 355 dy_vals = numpy.empty(0) 356 dxl = numpy.empty(0) 357 dxw = numpy.empty(0) 358 data1d = Data1D(x_vals, y_vals, dx_vals, dy_vals) 359 data1d.dxl = dxl 360 data1d.dxw = dxw 361 359 362 base_ns = "{0}{1}{2}".format("{", \ 360 363 CANSAS_NS.get(self.cansas_version).get("ns"), "}") … … 366 369 for node in dom: 367 370 try: 368 # Get the element name and set the current n s level371 # Get the element name and set the current names level 369 372 tagname = node.tag.replace(base_ns, "") 370 373 tagname_original = tagname 371 ns.append(tagname) 374 if tagname == "fitting_plug_in" or tagname == "pr_inversion" or\ 375 tagname == "invariant": 376 continue 377 names.append(tagname) 372 378 attr = node.attrib 373 379 children = node.getchildren() 380 if len(children) == 0: 381 children = None 374 382 save_data1d = data1d 375 383 … … 410 418 411 419 # Get where to store content 412 cs_values = constants._iterate_namespace(ns)420 cs_values = CONSTANTS.iterate_namespace(names) 413 421 # If the element is a child element, recurse 414 422 if children is not None: 415 423 # Returned value is new Data1D object with all previous and 416 424 # new values in it. 417 data1d, extras = self._parse_entry(node, ns, data1d, extras) 425 data1d, extras = self._parse_entry(node, 426 names, data1d, extras) 418 427 419 428 #Get the information from the node … … 488 497 pass 489 498 490 except TypeError :499 except TypeError as e: 491 500 pass 492 501 except Exception as e: … … 509 518 else: 510 519 save_data1d = data1d 511 data1d = save_data1d 512 # Remove tagname from ns to restore original base 513 ns.remove(tagname_original) 514 520 if tagname_original == "fitting_plug_in" or \ 521 tagname_original == "invariant" or \ 522 tagname_original == "pr_inversion": 523 pass 524 else: 525 data1d = save_data1d 526 # Remove tagname from names to restore original base 527 names.remove(tagname_original) 515 528 return data1d, extras 516 529 530 517 531 def _to_xml_doc(self, datainfo): 518 532 """ … … 521 535 :param datainfo: Data1D object 522 536 """ 523 524 537 if not issubclass(datainfo.__class__, Data1D): 525 538 raise RuntimeError, "The cansas writer expects a Data1D instance" 526 539 527 540 # Get PIs and create root element 528 pis = self.reader.return_processing_instructions() 529 doc = self.reader.create_tree(pis[0]) 530 i = 1 531 for i in range(1,len(pis) - 1): 532 doc = self.reader.append(pis[i], doc) 541 pis = self.return_processing_instructions() 542 if len(pis) > 0: 543 pi_tree = self.create_tree(pis[0]) 544 i = 1 545 for i in range(1,len(pis) - 1): 546 pi_tree = self.append(pis[i], pi_tree) 547 pi_string = self.to_string(pi_tree) 548 else: 549 pi_string = "" 533 550 534 551 # Define namespaces and create SASroot object … … 540 557 else: 541 558 url = "http://svn.smallangles.net/svn/canSAS/1dwg/trunk/" 542 schema Location = "{0} {1}cansas1d.xsd".format(ns, url)543 attrib = {"{" + xsi + "}schemaLocation" : schema Location,559 schema_location = "{0} {1}cansas1d.xsd".format(ns, url) 560 attrib = {"{" + xsi + "}schemaLocation" : schema_location, 544 561 "version" : version} 545 562 nsmap = {'xsi' : xsi, None: ns} 546 563 547 main_node = self. reader.create_element("{" + ns + "}SASroot", \564 main_node = self.create_element("{" + ns + "}SASroot", \ 548 565 attrib = attrib, \ 549 566 nsmap = nsmap) 550 567 551 568 # Create ElementTree, append SASroot and apply processing instructions 552 base_string = self.reader.toString(doc) + \ 553 self.reader.toString(main_node) 554 base_element = self.reader.create_element_from_string(base_string) 555 doc = self.reader.create_tree(base_element) 569 base_string = pi_string + self.to_string(main_node) 570 base_element = self.create_element_from_string(base_string) 571 doc = self.create_tree(base_element) 556 572 557 573 # Create SASentry Element 558 entry_node = self. reader.create_element("SASentry")574 entry_node = self.create_element("SASentry") 559 575 root = doc.getroot() 560 576 root.append(entry_node) … … 576 592 577 593 # Data info 578 node = self. reader.create_element("SASdata")579 self. reader.append(node, entry_node)594 node = self.create_element("SASdata") 595 self.append(node, entry_node) 580 596 581 597 for i in range(len(datainfo.x)): 582 pt = self. reader.create_element("Idata")598 pt = self.create_element("Idata") 583 599 node.append(pt) 584 600 self.write_node(pt, "Q", datainfo.x[i], {'unit': datainfo.x_unit}) … … 598 614 self.write_node(pt, "dQl", datainfo.dxl[i], 599 615 {'unit': datainfo.x_unit}) 600 616 601 617 # Transmission Spectrum Info 602 618 for i in range(len(datainfo.trans_spectrum)): 603 619 spectrum = datainfo.trans_spectrum[i] 604 node = self. reader.create_element("SAStransmission_spectrum",620 node = self.create_element("SAStransmission_spectrum", 605 621 {"name" : spectrum.name}) 606 self. reader.append(node, entry_node)622 self.append(node, entry_node) 607 623 if isinstance(spectrum.timestamp, datetime.datetime): 608 624 node.setAttribute("timestamp", spectrum.timestamp) 609 625 for i in range(len(spectrum.wavelength)): 610 pt = self. reader.create_element("Tdata")626 pt = self.create_element("Tdata") 611 627 node.append(pt) 612 628 self.write_node(pt, "Lambda", spectrum.wavelength[i], … … 621 637 622 638 # Sample info 623 sample = self. reader.create_element("SASsample")639 sample = self.create_element("SASsample") 624 640 if datainfo.sample.name is not None: 625 self. reader.write_attribute(sample,641 self.write_attribute(sample, 626 642 "name", 627 643 str(datainfo.sample.name)) 628 self. reader.append(sample, entry_node)644 self.append(sample, entry_node) 629 645 self.write_node(sample, "ID", str(datainfo.sample.ID)) 630 646 self.write_node(sample, "thickness", datainfo.sample.thickness, … … 634 650 {"unit": datainfo.sample.temperature_unit}) 635 651 636 pos = self. reader.create_element("position")652 pos = self.create_element("position") 637 653 written = self.write_node(pos, 638 654 "x", … … 648 664 {"unit": datainfo.sample.position_unit}) 649 665 if written == True: 650 self. reader.append(pos, sample)651 652 ori = self. reader.create_element("orientation")666 self.append(pos, sample) 667 668 ori = self.create_element("orientation") 653 669 written = self.write_node(ori, "roll", 654 670 datainfo.sample.orientation.x, … … 661 677 {"unit": datainfo.sample.orientation_unit}) 662 678 if written == True: 663 self. reader.append(ori, sample)679 self.append(ori, sample) 664 680 665 681 for item in datainfo.sample.details: … … 667 683 668 684 # Instrument info 669 instr = self. reader.create_element("SASinstrument")670 self. reader.append(instr, entry_node)685 instr = self.create_element("SASinstrument") 686 self.append(instr, entry_node) 671 687 672 688 self.write_node(instr, "name", datainfo.instrument) 673 689 674 690 # Source 675 source = self. reader.create_element("SASsource")691 source = self.create_element("SASsource") 676 692 if datainfo.source.name is not None: 677 self. reader.write_attribute(source,693 self.write_attribute(source, 678 694 "name", 679 695 str(datainfo.source.name)) 680 self. reader.append(source, instr)696 self.append(source, instr) 681 697 if datainfo.source.radiation == None or datainfo.source.radiation == '': 682 698 datainfo.source.radiation = "neutron" 683 699 self.write_node(source, "radiation", datainfo.source.radiation) 684 700 685 size = self. reader.create_element("beam_size")701 size = self.create_element("beam_size") 686 702 if datainfo.source.beam_size_name is not None: 687 self. reader.write_attribute(size,703 self.write_attribute(size, 688 704 "name", 689 705 str(datainfo.source.beam_size_name)) … … 697 713 {"unit": datainfo.source.beam_size_unit}) 698 714 if written == True: 699 self. reader.append(size, source)715 self.append(size, source) 700 716 701 717 self.write_node(source, "beam_shape", datainfo.source.beam_shape) … … 718 734 datainfo.collimation.append(coll) 719 735 for item in datainfo.collimation: 720 coll = self. reader.create_element("SAScollimation")736 coll = self.create_element("SAScollimation") 721 737 if item.name is not None: 722 self. reader.write_attribute(coll, "name", str(item.name))723 self. reader.append(coll, instr)738 self.write_attribute(coll, "name", str(item.name)) 739 self.append(coll, instr) 724 740 725 741 self.write_node(coll, "length", item.length, … … 727 743 728 744 for apert in item.aperture: 729 ap = self. reader.create_element("aperture")745 ap = self.create_element("aperture") 730 746 if apert.name is not None: 731 self. reader.write_attribute(ap, "name", str(apert.name))747 self.write_attribute(ap, "name", str(apert.name)) 732 748 if apert.type is not None: 733 self. reader.write_attribute(ap, "type", str(apert.type))734 self. reader.append(ap, coll)735 736 size = self. reader.create_element("size")749 self.write_attribute(ap, "type", str(apert.type)) 750 self.append(ap, coll) 751 752 size = self.create_element("size") 737 753 if apert.size_name is not None: 738 self. reader.write_attribute(size,754 self.write_attribute(size, 739 755 "name", 740 756 str(apert.size_name)) … … 746 762 {"unit": apert.size_unit}) 747 763 if written == True: 748 self. reader.append(size, ap)764 self.append(size, ap) 749 765 750 766 self.write_node(ap, "distance", apert.distance, … … 758 774 759 775 for item in datainfo.detector: 760 det = self. reader.create_element("SASdetector")776 det = self.create_element("SASdetector") 761 777 written = self.write_node(det, "name", item.name) 762 778 written = written | self.write_node(det, "SDD", item.distance, 763 779 {"unit": item.distance_unit}) 764 780 if written == True: 765 self. reader.append(det, instr)781 self.append(det, instr) 766 782 767 off = self. reader.create_element("offset")783 off = self.create_element("offset") 768 784 written = self.write_node(off, "x", item.offset.x, 769 785 {"unit": item.offset_unit}) … … 773 789 {"unit": item.offset_unit}) 774 790 if written == True: 775 self. reader.append(off, det)776 777 ori = self. reader.create_element("orientation")791 self.append(off, det) 792 793 ori = self.create_element("orientation") 778 794 written = self.write_node(ori, "roll", item.orientation.x, 779 795 {"unit": item.orientation_unit}) … … 785 801 {"unit": item.orientation_unit}) 786 802 if written == True: 787 self. reader.append(ori, det)803 self.append(ori, det) 788 804 789 center = self. reader.create_element("beam_center")805 center = self.create_element("beam_center") 790 806 written = self.write_node(center, "x", item.beam_center.x, 791 807 {"unit": item.beam_center_unit}) … … 797 813 {"unit": item.beam_center_unit}) 798 814 if written == True: 799 self. reader.append(center, det)800 801 pix = self. reader.create_element("pixel_size")815 self.append(center, det) 816 817 pix = self.create_element("pixel_size") 802 818 written = self.write_node(pix, "x", item.pixel_size.x, 803 819 {"unit": item.pixel_size_unit}) … … 810 826 {"unit": item.slit_length_unit}) 811 827 if written == True: 812 self. reader.append(pix, det)828 self.append(pix, det) 813 829 814 830 # Processes info 815 831 for item in datainfo.process: 816 node = self. reader.create_element("SASprocess")817 self. reader.append(node, entry_node)832 node = self.create_element("SASprocess") 833 self.append(node, entry_node) 818 834 819 835 self.write_node(node, "name", item.name) … … 831 847 # Note info 832 848 if len(datainfo.notes) == 0: 833 node = self. reader.create_element("SASnote")834 self. reader.append(node, entry_node)849 node = self.create_element("SASnote") 850 self.append(node, entry_node) 835 851 else: 836 852 for item in datainfo.notes: 837 node = self. reader.create_element("SASnote")838 self. reader.write_text(node, item)839 self. reader.append(node, entry_node)853 node = self.create_element("SASnote") 854 self.write_text(node, item) 855 self.append(node, entry_node) 840 856 841 857 842 858 # Return the document, and the SASentry node associated with 843 # the data we just wrote 859 # the data we just wrote 860 # If the calling function was not the cansas reader, return a minidom 861 # object rather than an lxml object. 862 863 frm = inspect.stack()[1] 864 mod_name = frm[1].replace("\\", "/").replace(".pyc", "") 865 mod_name = mod_name.replace(".py", "") 866 mod = mod_name.split("/readers/") 867 mod_name = mod[1] 868 if mod_name != "cansas_reader": 869 string = self.to_string(doc, pp=False) 870 doc = parseString(string) 871 node_name = entry_node.tag 872 node_list = doc.getElementsByTagName(node_name) 873 entry_node = node_list.item(0) 874 844 875 return doc, entry_node 845 876 846 877 847 def write_node(self, parent, name, value, attr= {}):878 def write_node(self, parent, name, value, attr=None): 848 879 """ 849 880 :param doc: document DOM … … 856 887 """ 857 888 if value is not None: 858 parent = self. reader.ebuilder(parent, name, value, attr)889 parent = self.ebuilder(parent, name, value, attr) 859 890 return True 860 891 return False … … 872 903 # Write the file 873 904 fd = open(filename, 'w') 874 if self. reader.encoding == None:875 self. reader.encoding = "UTF-8"876 doc.write(fd, encoding=self. reader.encoding,905 if self.encoding == None: 906 self.encoding = "UTF-8" 907 doc.write(fd, encoding=self.encoding, 877 908 pretty_print=True, xml_declaration=True) 878 909 fd.close() 879 910 911 912 # DO NOT REMOVE - used in saving and loading panel states. 913 def _store_float(self, location, node, variable, storage, optional=True): 914 """ 915 Get the content of a xpath location and store 916 the result. Check that the units are compatible 917 with the destination. The value is expected to 918 be a float. 919 920 The xpath location might or might not exist. 921 If it does not exist, nothing is done 922 923 :param location: xpath location to fetch 924 :param node: node to read the data from 925 :param variable: name of the data member to store it in [string] 926 :param storage: data object that has the 'variable' data member 927 :param optional: if True, no exception will be raised 928 if unit conversion can't be done 929 930 :raise ValueError: raised when the units are not recognized 931 """ 932 entry = get_content(location, node) 933 try: 934 value = float(entry.text) 935 except: 936 value = None 937 938 if value is not None: 939 # If the entry has units, check to see that they are 940 # compatible with what we currently have in the data object 941 units = entry.get('unit') 942 if units is not None: 943 toks = variable.split('.') 944 local_unit = None 945 exec "local_unit = storage.%s_unit" % toks[0] 946 if local_unit != None and units.lower() != local_unit.lower(): 947 if HAS_CONVERTER == True: 948 try: 949 conv = Converter(units) 950 exec "storage.%s = %g" % (variable, 951 conv(value, units=local_unit)) 952 except: 953 exc_type, exc_value, exc_traceback = sys.exc_info() 954 err_mess = "CanSAS reader: could not convert" 955 err_mess += " %s unit [%s]; expecting [%s]\n %s" \ 956 % (variable, units, local_unit, exc_value) 957 self.errors.append(err_mess) 958 if optional: 959 logging.info(err_mess) 960 else: 961 raise ValueError, err_mess 962 else: 963 err_mess = "CanSAS reader: unrecognized %s unit [%s];"\ 964 % (variable, units) 965 err_mess += " expecting [%s]" % local_unit 966 self.errors.append(err_mess) 967 if optional: 968 logging.info(err_mess) 969 else: 970 raise ValueError, err_mess 971 else: 972 exec "storage.%s = value" % variable 973 else: 974 exec "storage.%s = value" % variable 975 976 977 # DO NOT REMOVE - used in saving and loading panel states. 978 def _store_content(self, location, node, variable, storage): 979 """ 980 Get the content of a xpath location and store 981 the result. The value is treated as a string. 982 983 The xpath location might or might not exist. 984 If it does not exist, nothing is done 985 986 :param location: xpath location to fetch 987 :param node: node to read the data from 988 :param variable: name of the data member to store it in [string] 989 :param storage: data object that has the 'variable' data member 990 991 :return: return a list of errors 992 """ 993 entry = get_content(location, node) 994 if entry is not None and entry.text is not None: 995 exec "storage.%s = entry.text.strip()" % variable -
src/sans/dataloader/readers/xml_reader.py
r2e3b055 rac5b69d 17 17 from lxml import etree 18 18 from lxml.builder import E 19 parser = etree.ETCompatXMLParser(remove_comments=True, remove_pis=False) 19 20 PARSER = etree.ETCompatXMLParser(remove_comments=True, remove_pis=False) 20 21 21 22 class XMLreader(): 23 """ 24 Generic XML read and write class. Mostly helper functions. 25 Makes reading/writing XML a bit easier than calling lxml libraries directly. 26 27 :Dependencies: 28 This class requires lxml 2.3 or higher. 29 """ 22 30 23 31 xml = None … … 27 35 schemadoc = None 28 36 encoding = None 29 processing Instructions = None37 processing_instructions = None 30 38 31 39 def __init__(self, xml = None, schema = None, root = None): 32 40 self.xml = xml 33 41 self.schema = schema 34 self.processing Instructions = {}42 self.processing_instructions = {} 35 43 if xml is not None: 36 self.set XMLFile(xml, root)44 self.set_xml_file(xml, root) 37 45 else: 38 46 self.xmldoc = None 39 47 self.xmlroot = None 40 48 if schema is not None: 41 self.set Schema(schema)49 self.set_schema(schema) 42 50 else: 43 51 self.schemadoc = None … … 47 55 Read in an XML file into memory and return an lxml dictionary 48 56 """ 49 if self.validate XML():50 self.xmldoc = etree.parse(self.xml, parser = parser)57 if self.validate_xml(): 58 self.xmldoc = etree.parse(self.xml, parser = PARSER) 51 59 else: 52 raise etree. ValidationError(self, self.findInvalidXML())60 raise etree.XMLSchemaValidateError(self, self.find_invalid_xml()) 53 61 return self.xmldoc 54 62 55 def set XMLFile(self, xml, root = None):63 def set_xml_file(self, xml, root = None): 56 64 """ 57 65 Set the XML file and parse … … 59 67 try: 60 68 self.xml = xml 61 self.xmldoc = etree.parse(self.xml, parser = parser)69 self.xmldoc = etree.parse(self.xml, parser = PARSER) 62 70 self.xmlroot = self.xmldoc.getroot() 63 71 except Exception: … … 66 74 self.xmlroot = None 67 75 68 def set Schema(self, schema):76 def set_schema(self, schema): 69 77 """ 70 78 Set the schema file and parse … … 72 80 try: 73 81 self.schema = schema 74 self.schemadoc = etree.parse(self.schema, parser = parser)82 self.schemadoc = etree.parse(self.schema, parser = PARSER) 75 83 except Exception: 76 84 self.schema = None 77 85 self.schemadoc = None 78 86 79 def validate XML(self):87 def validate_xml(self): 80 88 """ 81 89 Checks to see if the XML file meets the schema … … 83 91 valid = True 84 92 if self.schema is not None: 85 self.parse SchemaAndDoc()86 schema Check = etree.XMLSchema(self.schemadoc)87 valid = schema Check.validate(self.xmldoc)93 self.parse_schema_and_doc() 94 schema_check = etree.XMLSchema(self.schemadoc) 95 valid = schema_check.validate(self.xmldoc) 88 96 return valid 89 97 90 def find InvalidXML(self):98 def find_invalid_xml(self): 91 99 """ 92 100 Finds the first offending element that should not be present in XML file 93 101 """ 94 first Error = ""95 self.parse SchemaAndDoc()102 first_error = "" 103 self.parse_schema_and_doc() 96 104 schema = etree.XMLSchema(self.schemadoc) 97 105 try: 98 first Error = schema.assertValid(self.xmldoc)106 first_error = schema.assertValid(self.xmldoc) 99 107 except etree.DocumentInvalid as e: 100 first Error = str(e)101 return first Error102 103 def parse SchemaAndDoc(self):108 first_error = str(e) 109 return first_error 110 111 def parse_schema_and_doc(self): 104 112 """ 105 113 Creates a dictionary of the parsed schema and xml files. 106 114 """ 107 self.set XMLFile(self.xml)108 self.set Schema(self.schema)109 110 def to String(self, elem, pp=False, encoding=None):115 self.set_xml_file(self.xml) 116 self.set_schema(self.schema) 117 118 def to_string(self, elem, pp=False, encoding=None): 111 119 """ 112 120 Converts an etree element into a string … … 129 137 return dic 130 138 131 def set ProcessingInstructions(self):139 def set_processing_instructions(self): 132 140 """ 133 141 Take out all processing instructions and create a dictionary from them … … 135 143 """ 136 144 dic = {} 137 p i= self.xmlroot.getprevious()138 while p iis not None:139 pi_string = self.to String(pi)145 proc_instr = self.xmlroot.getprevious() 146 while proc_instr is not None: 147 pi_string = self.to_string(proc_instr) 140 148 if "?>\n<?" in pi_string: 141 149 pi_string = pi_string.split("?>\n<?") … … 145 153 for item in pi_string: 146 154 dic = self.break_processing_instructions(item, dic) 147 p i = pi.getprevious()155 proc_instr = proc_instr.getprevious() 148 156 if 'xml' in dic: 149 self.set Encoding(dic['xml'])157 self.set_encoding(dic['xml']) 150 158 del dic['xml'] 151 self.processing Instructions = dic152 153 def set Encoding(self, attr_str):159 self.processing_instructions = dic 160 161 def set_encoding(self, attr_str): 154 162 """ 155 163 Find the encoding in the xml declaration and save it as a string … … 169 177 self.encoding = None 170 178 171 def _create_unique_key(self, dictionary, name, i= 0):179 def _create_unique_key(self, dictionary, name, numb = 0): 172 180 """ 173 181 Create a unique key value for any dictionary to prevent overwriting … … 176 184 :param dictionary: A dictionary with any number of entries 177 185 :param name: The index of the item to be added to dictionary 178 :param i: The number to be appended to the name, starts at 0186 :param numb: The number to be appended to the name, starts at 0 179 187 """ 180 188 if dictionary.get(name) is not None: 181 i+= 1189 numb += 1 182 190 name = name.split("_")[0] 183 name += "_{0}".format( i)184 name = self._create_unique_key(dictionary, name, i)191 name += "_{0}".format(numb) 192 name = self._create_unique_key(dictionary, name, numb) 185 193 return name 186 194 … … 193 201 return etree.ElementTree(root) 194 202 195 def create_element_from_string(self, s):203 def create_element_from_string(self, xml_string): 196 204 """ 197 205 Create an element from an XML string 198 206 199 :param s: A string of xml200 """ 201 return etree.fromstring( s)202 203 def create_element(self, name, attrib= {}, nsmap=None):207 :param xml_string: A string of xml 208 """ 209 return etree.fromstring(xml_string) 210 211 def create_element(self, name, attrib=None, nsmap=None): 204 212 """ 205 213 Create an XML element for writing to file … … 207 215 :param name: The name of the element to be created 208 216 """ 217 if attrib == None: 218 attrib = {} 209 219 return etree.Element(name, attrib, nsmap) 210 220 … … 237 247 """ 238 248 pi_list = [] 239 for key in self.processingInstructions: 240 value = self.processingInstructions.get(key) 241 pi = etree.ProcessingInstruction(key, value) 242 pi_list.append(pi) 249 if self.processing_instructions is not None: 250 for key in self.processing_instructions: 251 value = self.processing_instructions.get(key) 252 pi_item = etree.ProcessingInstruction(key, value) 253 pi_list.append(pi_item) 243 254 return pi_list 244 255 … … 253 264 return tree 254 265 255 def ebuilder(self, parent, elementname, text=None, attrib={}): 266 def ebuilder(self, parent, elementname, text=None, attrib=None): 267 """ 268 Use lxml E builder class with arbitrary inputs. 269 270 :param parnet: The parent element to append a child to 271 :param elementname: The name of the child in string form 272 :param text: The element text 273 :param attrib: A dictionary of attribute names to attribute values 274 """ 256 275 text = str(text) 276 if attrib == None: 277 attrib = {} 257 278 elem = E(elementname, attrib, text) 258 279 parent = parent.append(elem)
Note: See TracChangeset
for help on using the changeset viewer.