- Timestamp:
- May 5, 2014 3:41:43 PM (11 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:
- c81aa18
- Parents:
- 0089be3
- Location:
- src/sans
- Files:
-
- 4 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 rac5b69d 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": 375 continue 376 names.append(tagname) 372 377 attr = node.attrib 373 378 children = node.getchildren() 379 if len(children) == 0: 380 children = None 374 381 save_data1d = data1d 375 382 … … 410 417 411 418 # Get where to store content 412 cs_values = constants._iterate_namespace(ns)419 cs_values = CONSTANTS.iterate_namespace(names) 413 420 # If the element is a child element, recurse 414 421 if children is not None: 415 422 # Returned value is new Data1D object with all previous and 416 423 # new values in it. 417 data1d, extras = self._parse_entry(node, ns, data1d, extras) 424 data1d, extras = self._parse_entry(node, 425 names, data1d, extras) 418 426 419 427 #Get the information from the node … … 488 496 pass 489 497 490 except TypeError :498 except TypeError as e: 491 499 pass 492 500 except Exception as e: … … 509 517 else: 510 518 save_data1d = data1d 511 data1d = save_data1d512 # Remove tagname from ns to restore original base513 ns.remove(tagname_original)514 519 if tagname_original != "fitting_plug_in": 520 data1d = save_data1d 521 # Remove tagname from names to restore original base 522 names.remove(tagname_original) 515 523 return data1d, extras 516 524 525 517 526 def _to_xml_doc(self, datainfo): 518 527 """ … … 526 535 527 536 # 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) 537 pis = self.return_processing_instructions() 538 if len(pis) > 0: 539 pi_tree = self.create_tree(pis[0]) 540 i = 1 541 for i in range(1,len(pis) - 1): 542 pi_tree = self.append(pis[i], pi_tree) 543 pi_string = self.to_string(pi_tree) 544 else: 545 pi_string = "" 533 546 534 547 # Define namespaces and create SASroot object … … 540 553 else: 541 554 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,555 schema_location = "{0} {1}cansas1d.xsd".format(ns, url) 556 attrib = {"{" + xsi + "}schemaLocation" : schema_location, 544 557 "version" : version} 545 558 nsmap = {'xsi' : xsi, None: ns} 546 559 547 main_node = self. reader.create_element("{" + ns + "}SASroot", \560 main_node = self.create_element("{" + ns + "}SASroot", \ 548 561 attrib = attrib, \ 549 562 nsmap = nsmap) 550 563 551 564 # 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) 565 base_string = pi_string + self.to_string(main_node) 566 base_element = self.create_element_from_string(base_string) 567 doc = self.create_tree(base_element) 556 568 557 569 # Create SASentry Element 558 entry_node = self. reader.create_element("SASentry")570 entry_node = self.create_element("SASentry") 559 571 root = doc.getroot() 560 572 root.append(entry_node) … … 576 588 577 589 # Data info 578 node = self. reader.create_element("SASdata")579 self. reader.append(node, entry_node)590 node = self.create_element("SASdata") 591 self.append(node, entry_node) 580 592 581 593 for i in range(len(datainfo.x)): 582 pt = self. reader.create_element("Idata")594 pt = self.create_element("Idata") 583 595 node.append(pt) 584 596 self.write_node(pt, "Q", datainfo.x[i], {'unit': datainfo.x_unit}) … … 598 610 self.write_node(pt, "dQl", datainfo.dxl[i], 599 611 {'unit': datainfo.x_unit}) 600 612 601 613 # Transmission Spectrum Info 602 614 for i in range(len(datainfo.trans_spectrum)): 603 615 spectrum = datainfo.trans_spectrum[i] 604 node = self. reader.create_element("SAStransmission_spectrum",616 node = self.create_element("SAStransmission_spectrum", 605 617 {"name" : spectrum.name}) 606 self. reader.append(node, entry_node)618 self.append(node, entry_node) 607 619 if isinstance(spectrum.timestamp, datetime.datetime): 608 620 node.setAttribute("timestamp", spectrum.timestamp) 609 621 for i in range(len(spectrum.wavelength)): 610 pt = self. reader.create_element("Tdata")622 pt = self.create_element("Tdata") 611 623 node.append(pt) 612 624 self.write_node(pt, "Lambda", spectrum.wavelength[i], … … 621 633 622 634 # Sample info 623 sample = self. reader.create_element("SASsample")635 sample = self.create_element("SASsample") 624 636 if datainfo.sample.name is not None: 625 self. reader.write_attribute(sample,637 self.write_attribute(sample, 626 638 "name", 627 639 str(datainfo.sample.name)) 628 self. reader.append(sample, entry_node)640 self.append(sample, entry_node) 629 641 self.write_node(sample, "ID", str(datainfo.sample.ID)) 630 642 self.write_node(sample, "thickness", datainfo.sample.thickness, … … 634 646 {"unit": datainfo.sample.temperature_unit}) 635 647 636 pos = self. reader.create_element("position")648 pos = self.create_element("position") 637 649 written = self.write_node(pos, 638 650 "x", … … 648 660 {"unit": datainfo.sample.position_unit}) 649 661 if written == True: 650 self. reader.append(pos, sample)651 652 ori = self. reader.create_element("orientation")662 self.append(pos, sample) 663 664 ori = self.create_element("orientation") 653 665 written = self.write_node(ori, "roll", 654 666 datainfo.sample.orientation.x, … … 661 673 {"unit": datainfo.sample.orientation_unit}) 662 674 if written == True: 663 self. reader.append(ori, sample)675 self.append(ori, sample) 664 676 665 677 for item in datainfo.sample.details: … … 667 679 668 680 # Instrument info 669 instr = self. reader.create_element("SASinstrument")670 self. reader.append(instr, entry_node)681 instr = self.create_element("SASinstrument") 682 self.append(instr, entry_node) 671 683 672 684 self.write_node(instr, "name", datainfo.instrument) 673 685 674 686 # Source 675 source = self. reader.create_element("SASsource")687 source = self.create_element("SASsource") 676 688 if datainfo.source.name is not None: 677 self. reader.write_attribute(source,689 self.write_attribute(source, 678 690 "name", 679 691 str(datainfo.source.name)) 680 self. reader.append(source, instr)692 self.append(source, instr) 681 693 if datainfo.source.radiation == None or datainfo.source.radiation == '': 682 694 datainfo.source.radiation = "neutron" 683 695 self.write_node(source, "radiation", datainfo.source.radiation) 684 696 685 size = self. reader.create_element("beam_size")697 size = self.create_element("beam_size") 686 698 if datainfo.source.beam_size_name is not None: 687 self. reader.write_attribute(size,699 self.write_attribute(size, 688 700 "name", 689 701 str(datainfo.source.beam_size_name)) … … 697 709 {"unit": datainfo.source.beam_size_unit}) 698 710 if written == True: 699 self. reader.append(size, source)711 self.append(size, source) 700 712 701 713 self.write_node(source, "beam_shape", datainfo.source.beam_shape) … … 718 730 datainfo.collimation.append(coll) 719 731 for item in datainfo.collimation: 720 coll = self. reader.create_element("SAScollimation")732 coll = self.create_element("SAScollimation") 721 733 if item.name is not None: 722 self. reader.write_attribute(coll, "name", str(item.name))723 self. reader.append(coll, instr)734 self.write_attribute(coll, "name", str(item.name)) 735 self.append(coll, instr) 724 736 725 737 self.write_node(coll, "length", item.length, … … 727 739 728 740 for apert in item.aperture: 729 ap = self. reader.create_element("aperture")741 ap = self.create_element("aperture") 730 742 if apert.name is not None: 731 self. reader.write_attribute(ap, "name", str(apert.name))743 self.write_attribute(ap, "name", str(apert.name)) 732 744 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")745 self.write_attribute(ap, "type", str(apert.type)) 746 self.append(ap, coll) 747 748 size = self.create_element("size") 737 749 if apert.size_name is not None: 738 self. reader.write_attribute(size,750 self.write_attribute(size, 739 751 "name", 740 752 str(apert.size_name)) … … 746 758 {"unit": apert.size_unit}) 747 759 if written == True: 748 self. reader.append(size, ap)760 self.append(size, ap) 749 761 750 762 self.write_node(ap, "distance", apert.distance, … … 758 770 759 771 for item in datainfo.detector: 760 det = self. reader.create_element("SASdetector")772 det = self.create_element("SASdetector") 761 773 written = self.write_node(det, "name", item.name) 762 774 written = written | self.write_node(det, "SDD", item.distance, 763 775 {"unit": item.distance_unit}) 764 776 if written == True: 765 self. reader.append(det, instr)777 self.append(det, instr) 766 778 767 off = self. reader.create_element("offset")779 off = self.create_element("offset") 768 780 written = self.write_node(off, "x", item.offset.x, 769 781 {"unit": item.offset_unit}) … … 773 785 {"unit": item.offset_unit}) 774 786 if written == True: 775 self. reader.append(off, det)776 777 ori = self. reader.create_element("orientation")787 self.append(off, det) 788 789 ori = self.create_element("orientation") 778 790 written = self.write_node(ori, "roll", item.orientation.x, 779 791 {"unit": item.orientation_unit}) … … 785 797 {"unit": item.orientation_unit}) 786 798 if written == True: 787 self. reader.append(ori, det)799 self.append(ori, det) 788 800 789 center = self. reader.create_element("beam_center")801 center = self.create_element("beam_center") 790 802 written = self.write_node(center, "x", item.beam_center.x, 791 803 {"unit": item.beam_center_unit}) … … 797 809 {"unit": item.beam_center_unit}) 798 810 if written == True: 799 self. reader.append(center, det)800 801 pix = self. reader.create_element("pixel_size")811 self.append(center, det) 812 813 pix = self.create_element("pixel_size") 802 814 written = self.write_node(pix, "x", item.pixel_size.x, 803 815 {"unit": item.pixel_size_unit}) … … 810 822 {"unit": item.slit_length_unit}) 811 823 if written == True: 812 self. reader.append(pix, det)824 self.append(pix, det) 813 825 814 826 # Processes info 815 827 for item in datainfo.process: 816 node = self. reader.create_element("SASprocess")817 self. reader.append(node, entry_node)828 node = self.create_element("SASprocess") 829 self.append(node, entry_node) 818 830 819 831 self.write_node(node, "name", item.name) … … 831 843 # Note info 832 844 if len(datainfo.notes) == 0: 833 node = self. reader.create_element("SASnote")834 self. reader.append(node, entry_node)845 node = self.create_element("SASnote") 846 self.append(node, entry_node) 835 847 else: 836 848 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)849 node = self.create_element("SASnote") 850 self.write_text(node, item) 851 self.append(node, entry_node) 840 852 841 853 842 854 # Return the document, and the SASentry node associated with 843 855 # the data we just wrote 856 857 frm = inspect.stack()[1] 858 mod = inspect.getmodule(frm[0]) 859 mod_name = mod.__name__ 860 if mod_name != "sans.dataloader.readers.cansas_reader": 861 string = self.to_string(doc, pp=True) 862 doc = parseString(string) 863 node_name = entry_node.tag 864 node_list = doc.getElementsByTagName(node_name) 865 entry_node = node_list.item(0) 866 844 867 return doc, entry_node 845 868 846 869 847 def write_node(self, parent, name, value, attr= {}):870 def write_node(self, parent, name, value, attr=None): 848 871 """ 849 872 :param doc: document DOM … … 856 879 """ 857 880 if value is not None: 858 parent = self. reader.ebuilder(parent, name, value, attr)881 parent = self.ebuilder(parent, name, value, attr) 859 882 return True 860 883 return False … … 872 895 # Write the file 873 896 fd = open(filename, 'w') 874 if self. reader.encoding == None:875 self. reader.encoding = "UTF-8"876 doc.write(fd, encoding=self. reader.encoding,897 if self.encoding == None: 898 self.encoding = "UTF-8" 899 doc.write(fd, encoding=self.encoding, 877 900 pretty_print=True, xml_declaration=True) 878 901 fd.close() 879 902 903 904 # DO NOT REMOVE - used in saving and loading panel states. 905 def _store_float(self, location, node, variable, storage, optional=True): 906 """ 907 Get the content of a xpath location and store 908 the result. Check that the units are compatible 909 with the destination. The value is expected to 910 be a float. 911 912 The xpath location might or might not exist. 913 If it does not exist, nothing is done 914 915 :param location: xpath location to fetch 916 :param node: node to read the data from 917 :param variable: name of the data member to store it in [string] 918 :param storage: data object that has the 'variable' data member 919 :param optional: if True, no exception will be raised 920 if unit conversion can't be done 921 922 :raise ValueError: raised when the units are not recognized 923 """ 924 entry = get_content(location, node) 925 try: 926 value = float(entry.text) 927 except: 928 value = None 929 930 if value is not None: 931 # If the entry has units, check to see that they are 932 # compatible with what we currently have in the data object 933 units = entry.get('unit') 934 if units is not None: 935 toks = variable.split('.') 936 local_unit = None 937 exec "local_unit = storage.%s_unit" % toks[0] 938 if local_unit != None and units.lower() != local_unit.lower(): 939 if HAS_CONVERTER == True: 940 try: 941 conv = Converter(units) 942 exec "storage.%s = %g" % (variable, 943 conv(value, units=local_unit)) 944 except: 945 err_mess = "CanSAS reader: could not convert" 946 err_mess += " %s unit [%s]; expecting [%s]\n %s" \ 947 % (variable, units, local_unit, sys.exc_value) 948 self.errors.append(err_mess) 949 if optional: 950 logging.info(err_mess) 951 else: 952 raise ValueError, err_mess 953 else: 954 err_mess = "CanSAS reader: unrecognized %s unit [%s];"\ 955 % (variable, units) 956 err_mess += " expecting [%s]" % local_unit 957 self.errors.append(err_mess) 958 if optional: 959 logging.info(err_mess) 960 else: 961 raise ValueError, err_mess 962 else: 963 exec "storage.%s = value" % variable 964 else: 965 exec "storage.%s = value" % variable 966 967 968 # DO NOT REMOVE - used in saving and loading panel states. 969 def _store_content(self, location, node, variable, storage): 970 """ 971 Get the content of a xpath location and store 972 the result. The value is treated as a string. 973 974 The xpath location might or might not exist. 975 If it does not exist, nothing is done 976 977 :param location: xpath location to fetch 978 :param node: node to read the data from 979 :param variable: name of the data member to store it in [string] 980 :param storage: data object that has the 'variable' data member 981 982 :return: return a list of errors 983 """ 984 entry = get_content(location, node) 985 if entry is not None and entry.text is not None: 986 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) -
src/sans/perspectives/fitting/pagestate.py
reddb6ec rac5b69d 20 20 21 21 import xml.dom.minidom 22 from xml.dom.minidom import parseString 22 23 from lxml import etree 23 24 … … 672 673 # We are appending to an existing document 673 674 newdoc = doc 674 top_element = newdoc.createElement(FITTING_NODE_NAME) 675 try: 676 top_element = newdoc.createElement(FITTING_NODE_NAME) 677 except: 678 string = etree.tostring(doc, pretty_print=True) 679 newdoc = parseString(string) 680 top_element = newdoc.createElement(FITTING_NODE_NAME) 675 681 if entry_node is None: 676 682 newdoc.documentElement.appendChild(top_element) 677 683 else: 678 entry_node.appendChild(top_element) 679 684 try: 685 entry_node.appendChild(top_element) 686 except: 687 node_name = entry_node.tag 688 node_list = newdoc.getElementsByTagName(node_name) 689 entry_node = node_list.item(0) 690 entry_node.appendChild(top_element) 691 680 692 attr = newdoc.createAttribute("version") 681 693 attr.nodeValue = '1.0' … … 750 762 for item in list_of_state_parameters: 751 763 element = newdoc.createElement(item[0]) 752 com = "self._toXML_helper( list=self.%s,"764 com = "self._toXML_helper(thelist=self.%s," 753 765 com += " element=element, newdoc=newdoc)" 754 766 exec com % item[1] … … 762 774 return None 763 775 else: 764 return newdoc .toprettyxml()776 return newdoc 765 777 766 778 def _fromXML_helper(self, node, list): … … 1252 1264 state = PageState() 1253 1265 state.fromXML(node=nodes[0]) 1266 1254 1267 except: 1255 1268 logging.info("XML document does not contain fitting information.\n %s" % sys.exc_value) … … 1257 1270 return state 1258 1271 1259 def _parse_ entry(self, dom):1272 def _parse_save_state_entry(self, dom): 1260 1273 """ 1261 1274 Parse a SASentry … … 1268 1281 node = dom.xpath('ns:data_class', namespaces={'ns': CANSAS_NS}) 1269 1282 if not node or node[0].text.lstrip().rstrip() != "Data2D": 1270 return CansasReader._parse_entry(self, dom) 1283 return_value, _ = self._parse_entry(dom) 1284 numpy.trim_zeros(return_value.x) 1285 numpy.trim_zeros(return_value.y) 1286 numpy.trim_zeros(return_value.dy) 1287 size_dx = return_value.dx.size 1288 size_dxl = return_value.dxl.size 1289 size_dxw = return_value.dxw.size 1290 if size_dxl == 0 and size_dxw == 0: 1291 return_value.dxl = None 1292 return_value.dxw = None 1293 numpy.trim_zeros(return_value.dx) 1294 elif size_dx == 0: 1295 return_value.dx = None 1296 size_dx = size_dxl 1297 numpy.trim_zeros(return_value.dxl) 1298 numpy.trim_zeros(return_value.dxw) 1299 1300 return return_value, _ 1271 1301 1272 1302 #Parse 2D … … 1539 1569 for entry in entry_list: 1540 1570 try: 1541 sas_entry = self._parse_entry(entry)1571 sas_entry, _ = self._parse_save_state_entry(entry) 1542 1572 except: 1543 1573 raise … … 1608 1638 # Sanity check 1609 1639 if self.cansas == True: 1610 1611 1640 # Add fitting information to the XML document 1612 1641 doc = self.write_toXML(datainfo, fitstate) 1613 1642 # Write the XML document 1614 fd = open(filename, 'w')1615 fd.write(doc.toprettyxml())1616 fd.close()1617 1643 else: 1618 fitstate.toXML(file=filename) 1644 doc = fitstate.toXML(file=filename) 1645 1646 # Save the document no matter the type 1647 fd = open(filename, 'w') 1648 fd.write(doc.toprettyxml()) 1649 fd.close() 1619 1650 1620 1651 def write_toXML(self, datainfo=None, state=None): … … 1638 1669 state.data.run = [str(state.data.name)] 1639 1670 state.data.run_name[0] = state.data.name 1640 1671 1641 1672 if issubclass(state.data.__class__, 1642 1673 sans.dataloader.data_info.Data1D): … … 1648 1679 1649 1680 if state is not None: 1650 state.toXML(doc=doc, file=data.filename, entry_node=sasentry)1651 1681 doc = state.toXML(doc=doc, file=data.filename, entry_node=sasentry) 1682 1652 1683 return doc 1653 1684
Note: See TracChangeset
for help on using the changeset viewer.