Index: src/sas/sascalc/dataloader/data_info.py
===================================================================
--- src/sas/sascalc/dataloader/data_info.py	(revision b699768550de9d4b35b087234ec1d2a461922bab)
+++ src/sas/sascalc/dataloader/data_info.py	(revision d72567eac270b5ba960e7bfa2dac6f9cbc461dbe)
@@ -1073,4 +1073,5 @@
         clone.source = deepcopy(self.source)
         clone.collimation = deepcopy(self.collimation)
+        clone.trans_spectrum = deepcopy(self.trans_spectrum)
         clone.meta_data = deepcopy(self.meta_data)
         clone.errors = deepcopy(self.errors)
@@ -1226,2 +1227,51 @@
 
         return result
+
+
+def combine_data_info_with_plottable(data, datainfo):
+    """
+    A function that combines the DataInfo data in self.current_datainto with a plottable_1D or 2D data object.
+
+    :param data: A plottable_1D or plottable_2D data object
+    :return: A fully specified Data1D or Data2D object
+    """
+
+    final_dataset = None
+    if isinstance(data, plottable_1D):
+        final_dataset = Data1D(data.x, data.y)
+        final_dataset.dx = data.dx
+        final_dataset.dy = data.dy
+        final_dataset.dxl = data.dxl
+        final_dataset.dxw = data.dxw
+        final_dataset.xaxis(data._xaxis, data._xunit)
+        final_dataset.yaxis(data._yaxis, data._yunit)
+    elif isinstance(data, plottable_2D):
+        final_dataset = Data2D(data.data, data.err_data, data.qx_data, data.qy_data, data.q_data,
+                               data.mask, data.dqx_data, data.dqy_data)
+        final_dataset.xaxis(data._xaxis, data._xunit)
+        final_dataset.yaxis(data._yaxis, data._yunit)
+        final_dataset.zaxis(data._zaxis, data._zunit)
+    else:
+        return_string = "Should Never Happen: _combine_data_info_with_plottable input is not a plottable1d or " + \
+                        "plottable2d data object"
+        return return_string
+
+    final_dataset.xmax = data.xmax
+    final_dataset.ymax = data.ymax
+    final_dataset.xmin = data.xmin
+    final_dataset.ymin = data.ymin
+    final_dataset.title = datainfo.title
+    final_dataset.run = datainfo.run
+    final_dataset.run_name = datainfo.run_name
+    final_dataset.filename = datainfo.filename
+    final_dataset.notes = datainfo.notes
+    final_dataset.process = datainfo.process
+    final_dataset.instrument = datainfo.instrument
+    final_dataset.detector = datainfo.detector
+    final_dataset.sample = datainfo.sample
+    final_dataset.source = datainfo.source
+    final_dataset.collimation = datainfo.collimation
+    final_dataset.trans_spectrum = datainfo.trans_spectrum
+    final_dataset.meta_data = datainfo.meta_data
+    final_dataset.errors = datainfo.errors
+    return final_dataset
Index: src/sas/sascalc/dataloader/readers/cansas_reader.py
===================================================================
--- src/sas/sascalc/dataloader/readers/cansas_reader.py	(revision 8976865459a89ad49ea825edc2e2cae17b5b512b)
+++ src/sas/sascalc/dataloader/readers/cansas_reader.py	(revision 83b6408fbfaefa4819b955c697fef834d8f033f6)
@@ -34,4 +34,7 @@
 from xml.dom.minidom import parseString
 
+## TODO: Refactor to load multiple <SASData> as separate Data1D objects
+## TODO: Refactor to allow invalid XML, but give a useful warning when loaded
+
 _ZERO = 1e-16
 PREPROCESS = "xmlpreprocess"
@@ -133,5 +136,5 @@
         return False
 
-    def load_file_and_schema(self, xml_file):
+    def load_file_and_schema(self, xml_file, schema_path=""):
         """
         Loads the file and associates a schema, if a known schema exists
@@ -149,5 +152,6 @@
         # Generic values for the cansas file based on the version
         cansas_defaults = CANSAS_NS.get(self.cansas_version, "1.0")
-        schema_path = "{0}/sas/sascalc/dataloader/readers/schema/{1}".format\
+        if schema_path == "":
+            schema_path = "{0}/sas/sascalc/dataloader/readers/schema/{1}".format\
                 (base, cansas_defaults.get("schema")).replace("\\", "/")
 
@@ -156,5 +160,7 @@
         return cansas_defaults
 
-    def read(self, xml_file):
+    ## TODO: Test loading invalid CanSAS XML files and see if this works
+    ## TODO: Once works, try adding a warning that the data is invalid
+    def read(self, xml_file, schema_path=""):
         """
         Validate and read in an xml_file file in the canSAS format.
@@ -174,5 +180,5 @@
             if extension in self.ext or self.allow_all:
                 # Get the file location of
-                cansas_defaults = self.load_file_and_schema(xml_file)
+                cansas_defaults = self.load_file_and_schema(xml_file, schema_path)
 
                 # Try to load the file, but raise an error if unable to.
@@ -225,5 +231,14 @@
                 except:
                     # If the file does not match the schema, raise this error
-                    raise RuntimeError, "%s cannot be read" % xml_file
+                    schema_path = "{0}/sas/sascalc/dataloader/readers/schema/cansas1d_invalid.xsd"
+                    invalid_xml = self.find_invalid_xml()
+                    invalid_xml = "\n\nThe loaded xml file does not fully meet the CanSAS v1.x specification. SasView " + \
+                                  "loaded as much of the data as possible.\n\n" + invalid_xml
+                    self.errors.add(invalid_xml)
+                    self.set_schema(schema_path)
+                    if self.is_cansas():
+                        output = self.read(xml_file, schema_path)
+                    else:
+                        raise RuntimeError, "%s cannot be read" % xml_file
                 return output
         # Return a list of parsed entries that dataloader can manage
Index: src/sas/sascalc/dataloader/readers/cansas_reader_HDF5.py
===================================================================
--- src/sas/sascalc/dataloader/readers/cansas_reader_HDF5.py	(revision d398285d1a07fbcba8a3328a6db3de09fb8581df)
+++ src/sas/sascalc/dataloader/readers/cansas_reader_HDF5.py	(revision d72567eac270b5ba960e7bfa2dac6f9cbc461dbe)
@@ -9,6 +9,8 @@
 import sys
 
-from sas.sascalc.dataloader.data_info import plottable_1D, plottable_2D, Data1D, Data2D, Sample, Source
-from sas.sascalc.dataloader.data_info import Process, Aperture, Collimation, TransmissionSpectrum, Detector
+from sas.sascalc.dataloader.data_info import plottable_1D, plottable_2D, Data1D, Data2D, DataInfo, Process, Aperture
+from sas.sascalc.dataloader.data_info import Collimation, TransmissionSpectrum, Detector
+from sas.sascalc.dataloader.data_info import combine_data_info_with_plottable
+
 
 
@@ -18,8 +20,10 @@
     with file extension .h5/.H5. Any number of data sets may be present within the file and any dimensionality of data
     may be used. Currently 1D and 2D SAS data sets are supported, but future implementations will include 1D and 2D
-    SESANS data. This class assumes a single data set for each sasentry.
+    SESANS data.
+
+    Any number of SASdata sets may be present in a SASentry and the data within can be either 1D I(Q) or 2D I(Qx, Qy).
 
     :Dependencies:
-        The CanSAS HDF5 reader requires h5py v2.5.0 or later.
+        The CanSAS HDF5 reader requires h5py => v2.5.0 or later.
     """
 
@@ -32,8 +36,12 @@
     ## Raw file contents to be processed
     raw_data = None
-    ## Data set being modified
+    ## Data info currently being read in
+    current_datainfo = None
+    ## SASdata set currently being read in
     current_dataset = None
-    ## For recursion and saving purposes, remember parent objects
-    parent_list = None
+    ## List of plottable1D objects that should be linked to the current_datainfo
+    data1d = None
+    ## List of plottable2D objects that should be linked to the current_datainfo
+    data2d = None
     ## Data type name
     type_name = "CanSAS 2.0"
@@ -47,23 +55,4 @@
     output = None
 
-    def __init__(self):
-        """
-        Create the reader object and define initial states for class variables
-        """
-        self.current_dataset = None
-        self.datasets = []
-        self.raw_data = None
-        self.errors = set()
-        self.logging = []
-        self.parent_list = []
-        self.output = []
-        self.detector = Detector()
-        self.collimation = Collimation()
-        self.aperture = Aperture()
-        self.process = Process()
-        self.sample = Sample()
-        self.source = Source()
-        self.trans_spectrum  = TransmissionSpectrum()
-
     def read(self, filename):
         """
@@ -71,9 +60,9 @@
 
         :param filename: A path for an HDF5 formatted CanSAS 2D data file.
-        :return: List of Data1D/2D objects or a list of errors.
+        :return: List of Data1D/2D objects and/or a list of errors.
         """
 
         ## Reinitialize the class when loading a new data file to reset all class variables
-        self.__init__()
+        self.reset_class_variables()
         ## Check that the file exists
         if os.path.isfile(filename):
@@ -85,5 +74,5 @@
                 self.raw_data = h5py.File(filename, 'r')
                 ## Read in all child elements of top level SASroot
-                self.read_children(self.raw_data)
+                self.read_children(self.raw_data, [])
                 ## Add the last data set to the list of outputs
                 self.add_data_set()
@@ -91,5 +80,24 @@
         return self.output
 
-    def read_children(self, data, parent=u'SASroot'):
+    def reset_class_variables(self):
+        """
+        Create the reader object and define initial states for class variables
+        """
+        self.current_datainfo = None
+        self.current_dataset = None
+        self.data1d = []
+        self.data2d = []
+        self.raw_data = None
+        self.errors = set()
+        self.logging = []
+        self.output = []
+        self.parent_class = u''
+        self.detector = Detector()
+        self.collimation = Collimation()
+        self.aperture = Aperture()
+        self.process = Process()
+        self.trans_spectrum = TransmissionSpectrum()
+
+    def read_children(self, data, parent_list):
         """
         A recursive method for stepping through the hierarchical data file.
@@ -97,9 +105,5 @@
         :param data: h5py Group object of any kind
         :param parent: h5py Group parent name
-        :return: None
-        """
-
-        ## Create regex for base sasentry and for parent
-        parent_prog = re.compile(parent)
+        """
 
         ## Loop through each element of the parent and process accordingly
@@ -107,6 +111,4 @@
             ## Get all information for the current key
             value = data.get(key)
-            attr_keys = value.attrs.keys()
-            attr_values = value.attrs.values()
             if value.attrs.get(u'canSAS_class') is not None:
                 class_name = value.attrs.get(u'canSAS_class')
@@ -119,12 +121,15 @@
 
             if isinstance(value, h5py.Group):
-                ##TODO: Rework this for multiple SASdata objects within a single SASentry to allow for both 1D and 2D
-                ##TODO:     data within the same SASentry - One 1D and one 2D data object for all SASdata sets?
-                ## If this is a new sasentry, store the current data set and create a fresh Data1D/2D object
+                self.parent_class = class_name
+                parent_list.append(key)
+                ## If this is a new sasentry, store the current data sets and create a fresh Data1D/2D object
                 if class_prog.match(u'SASentry'):
                     self.add_data_set(key)
+                elif class_prog.match(u'SASdata'):
+                    self._initialize_new_data_set(parent_list)
                 ## Recursion step to access data within the group
-                self.read_children(value, class_name)
-                self.add_intermediate(class_name)
+                self.read_children(value, parent_list)
+                self.add_intermediate()
+                parent_list.remove(key)
 
             elif isinstance(value, h5py.Dataset):
@@ -136,15 +141,15 @@
                     unit = self._get_unit(value)
                     if key == u'definition':
-                        self.current_dataset.meta_data['reader'] = data_point
+                        self.current_datainfo.meta_data['reader'] = data_point
                     elif key == u'run':
-                        self.current_dataset.run.append(data_point)
+                        self.current_datainfo.run.append(data_point)
                     elif key == u'title':
-                        self.current_dataset.title = data_point
+                        self.current_datainfo.title = data_point
                     elif key == u'SASnote':
-                        self.current_dataset.notes.append(data_point)
+                        self.current_datainfo.notes.append(data_point)
 
                     ## I and Q Data
                     elif key == u'I':
-                        if type(self.current_dataset) is Data2D:
+                        if type(self.current_dataset) is plottable_2D:
                             self.current_dataset.data = np.append(self.current_dataset.data, data_point)
                             self.current_dataset.zaxis("Intensity", unit)
@@ -153,5 +158,5 @@
                             self.current_dataset.yaxis("Intensity", unit)
                     elif key == u'Idev':
-                        if type(self.current_dataset) is Data2D:
+                        if type(self.current_dataset) is plottable_2D:
                             self.current_dataset.err_data = np.append(self.current_dataset.err_data, data_point)
                         else:
@@ -159,5 +164,5 @@
                     elif key == u'Q':
                         self.current_dataset.xaxis("Q", unit)
-                        if type(self.current_dataset) is Data2D:
+                        if type(self.current_dataset) is plottable_2D:
                             self.current_dataset.q = np.append(self.current_dataset.q, data_point)
                         else:
@@ -177,58 +182,58 @@
 
                     ## Sample Information
-                    elif key == u'Title' and parent == u'SASsample':
-                        self.sample.name = data_point
-                    elif key == u'thickness' and parent == u'SASsample':
-                        self.sample.thickness = data_point
-                    elif key == u'temperature' and parent == u'SASsample':
-                        self.sample.temperature = data_point
+                    elif key == u'Title' and self.parent_class == u'SASsample':
+                        self.current_datainfo.sample.name = data_point
+                    elif key == u'thickness' and self.parent_class == u'SASsample':
+                        self.current_datainfo.sample.thickness = data_point
+                    elif key == u'temperature' and self.parent_class == u'SASsample':
+                        self.current_datainfo.sample.temperature = data_point
 
                     ## Instrumental Information
-                    elif key == u'name' and parent == u'SASinstrument':
-                        self.current_dataset.instrument = data_point
-                    elif key == u'name' and parent == u'SASdetector':
+                    elif key == u'name' and self.parent_class == u'SASinstrument':
+                        self.current_datainfo.instrument = data_point
+                    elif key == u'name' and self.parent_class == u'SASdetector':
                         self.detector.name = data_point
-                    elif key == u'SDD' and parent == u'SASdetector':
-                        self.detector.distance = data_point
+                    elif key == u'SDD' and self.parent_class == u'SASdetector':
+                        self.detector.distance = float(data_point)
                         self.detector.distance_unit = unit
-                    elif key == u'SSD' and parent == u'SAScollimation':
+                    elif key == u'SSD' and self.parent_class == u'SAScollimation':
                         self.collimation.length = data_point
                         self.collimation.length_unit = unit
-                    elif key == u'name' and parent == u'SAScollimation':
+                    elif key == u'name' and self.parent_class == u'SAScollimation':
                         self.collimation.name = data_point
 
                     ## Process Information
-                    elif key == u'name' and parent == u'SASprocess':
+                    elif key == u'name' and self.parent_class == u'SASprocess':
                         self.process.name = data_point
-                    elif key == u'Title' and parent == u'SASprocess':
+                    elif key == u'Title' and self.parent_class == u'SASprocess':
                         self.process.name = data_point
-                    elif key == u'description' and parent == u'SASprocess':
+                    elif key == u'description' and self.parent_class == u'SASprocess':
                         self.process.description = data_point
-                    elif key == u'date' and parent == u'SASprocess':
+                    elif key == u'date' and self.parent_class == u'SASprocess':
                         self.process.date = data_point
-                    elif parent == u'SASprocess':
+                    elif self.parent_class == u'SASprocess':
                         self.process.notes.append(data_point)
 
                     ## Transmission Spectrum
-                    elif key == u'T' and parent == u'SAStransmission_spectrum':
+                    elif key == u'T' and self.parent_class == u'SAStransmission_spectrum':
                         self.trans_spectrum.transmission.append(data_point)
-                    elif key == u'Tdev' and parent == u'SAStransmission_spectrum':
+                    elif key == u'Tdev' and self.parent_class == u'SAStransmission_spectrum':
                         self.trans_spectrum.transmission_deviation.append(data_point)
-                    elif key == u'lambda' and parent == u'SAStransmission_spectrum':
+                    elif key == u'lambda' and self.parent_class == u'SAStransmission_spectrum':
                         self.trans_spectrum.wavelength.append(data_point)
 
                     ## Other Information
-                    elif key == u'wavelength' and parent == u'SASdata':
-                        self.source.wavelength = data_point
-                        self.source.wavelength.unit = unit
-                    elif key == u'radiation' and parent == u'SASsource':
-                        self.source.radiation = data_point
-                    elif key == u'transmission' and parent == u'SASdata':
-                        self.sample.transmission = data_point
+                    elif key == u'wavelength' and self.parent_class == u'SASdata':
+                        self.current_datainfo.source.wavelength = data_point
+                        self.current_datainfo.source.wavelength.unit = unit
+                    elif key == u'radiation' and self.parent_class == u'SASsource':
+                        self.current_datainfo.source.radiation = data_point
+                    elif key == u'transmission' and self.parent_class == u'SASdata':
+                        self.current_datainfo.sample.transmission = data_point
 
                     ## Everything else goes in meta_data
                     else:
-                        new_key = self._create_unique_key(self.current_dataset.meta_data, key)
-                        self.current_dataset.meta_data[new_key] = data_point
+                        new_key = self._create_unique_key(self.current_datainfo.meta_data, key)
+                        self.current_datainfo.meta_data[new_key] = data_point
 
             else:
@@ -236,108 +241,42 @@
                 self.errors.add("ShouldNeverHappenException")
 
-    def add_intermediate(self, parent):
+    def add_intermediate(self):
         """
         This method stores any intermediate objects within the final data set after fully reading the set.
 
         :param parent: The NXclass name for the h5py Group object that just finished being processed
-        :return:
-        """
-
-        if parent == u'SASprocess':
-            self.current_dataset.process.append(self.process)
+        """
+
+        if self.parent_class == u'SASprocess':
+            self.current_datainfo.process.append(self.process)
             self.process = Process()
-        elif parent == u'SASdetector':
-            self.current_dataset.detector.append(self.detector)
+        elif self.parent_class == u'SASdetector':
+            self.current_datainfo.detector.append(self.detector)
             self.detector = Detector()
-        elif parent == u'SAStransmission_spectrum':
-            self.current_dataset.trans_spectrum.append(self.trans_spectrum)
+        elif self.parent_class == u'SAStransmission_spectrum':
+            self.current_datainfo.trans_spectrum.append(self.trans_spectrum)
             self.trans_spectrum = TransmissionSpectrum()
-        elif parent == u'SASsource':
-            self.current_dataset.source = self.source
-            self.source = Source()
-        elif parent == u'SASsample':
-            self.current_dataset.sample = self.sample
-            self.sample = Sample()
-        elif parent == u'SAScollimation':
-            self.current_dataset.collimation.append(self.collimation)
+        elif self.parent_class == u'SAScollimation':
+            self.current_datainfo.collimation.append(self.collimation)
             self.collimation = Collimation()
-        elif parent == u'SASaperture':
+        elif self.parent_class == u'SASaperture':
             self.collimation.aperture.append(self.aperture)
             self.aperture = Aperture()
+        elif self.parent_class == u'SASdata':
+            if type(self.current_dataset) is plottable_2D:
+                self.data2d.append(self.current_dataset)
+            elif type(self.current_dataset) is plottable_1D:
+                self.data1d.append(self.current_dataset)
 
     def final_data_cleanup(self):
         """
-        Does some final cleanup and formatting on self.current_dataset
-        """
-
-        ## Type cast data arrays to float64 and find min/max as appropriate
-        if type(self.current_dataset) is Data2D:
-            self.current_dataset.data = np.delete(self.current_dataset.data, [0])
-            self.current_dataset.data = self.current_dataset.data.astype(np.float64)
-            self.current_dataset.err_data = np.delete(self.current_dataset.err_data, [0])
-            self.current_dataset.err_data = self.current_dataset.err_data.astype(np.float64)
-            self.current_dataset.mask = np.delete(self.current_dataset.mask, [0])
-            if self.current_dataset.qx_data is not None:
-                self.current_dataset.qx_data = np.delete(self.current_dataset.qx_data, [0])
-                self.current_dataset.xmin = np.min(self.current_dataset.qx_data)
-                self.current_dataset.xmax = np.max(self.current_dataset.qx_data)
-                self.current_dataset.qx_data = self.current_dataset.qx_data.astype(np.float64)
-            if self.current_dataset.dqx_data is not None:
-                self.current_dataset.dqx_data = np.delete(self.current_dataset.dqx_data, [0])
-                self.current_dataset.dqx_data = self.current_dataset.dqx_data.astype(np.float64)
-            if self.current_dataset.qy_data is not None:
-                self.current_dataset.qy_data = np.delete(self.current_dataset.qy_data, [0])
-                self.current_dataset.ymin = np.min(self.current_dataset.qy_data)
-                self.current_dataset.ymax = np.max(self.current_dataset.qy_data)
-                self.current_dataset.qy_data = self.current_dataset.qy_data.astype(np.float64)
-            if self.current_dataset.dqy_data is not None:
-                self.current_dataset.dqy_data = np.delete(self.current_dataset.dqy_data, [0])
-                self.current_dataset.dqy_data = self.current_dataset.dqy_data.astype(np.float64)
-            if self.current_dataset.q_data is not None:
-                self.current_dataset.q_data = np.delete(self.current_dataset.q_data, [0])
-                self.current_dataset.q_data = self.current_dataset.q_data.astype(np.float64)
-            zeros = np.ones(self.current_dataset.data.size, dtype=bool)
-            try:
-                for i in range (0, self.current_dataset.mask.size - 1):
-                    zeros[i] = self.current_dataset.mask[i]
-            except:
-                self.errors.add(sys.exc_value)
-            self.current_dataset.mask = zeros
-
-            ## Calculate the actual Q matrix
-            try:
-                if self.current_dataset.q_data.size <= 1:
-                    self.current_dataset.q_data = np.sqrt(self.current_dataset.qx_data * self.current_dataset.qx_data +
-                            self.current_dataset.qy_data * self.current_dataset.qy_data)
-            except:
-                self.current_dataset.q_data = None
-
-        elif type(self.current_dataset) is Data1D:
-            if self.current_dataset.x is not None:
-                self.current_dataset.x = np.delete(self.current_dataset.x, [0])
-                self.current_dataset.x = self.current_dataset.x.astype(np.float64)
-                self.current_dataset.xmin = np.min(self.current_dataset.x)
-                self.current_dataset.xmax = np.max(self.current_dataset.x)
-            if self.current_dataset.y is not None:
-                self.current_dataset.y = np.delete(self.current_dataset.y, [0])
-                self.current_dataset.y = self.current_dataset.y.astype(np.float64)
-                self.current_dataset.ymin = np.min(self.current_dataset.y)
-                self.current_dataset.ymax = np.max(self.current_dataset.y)
-            if self.current_dataset.dx is not None:
-                self.current_dataset.dx = np.delete(self.current_dataset.dx, [0])
-                self.current_dataset.dx = self.current_dataset.dx.astype(np.float64)
-            if self.current_dataset.dxl is not None:
-                self.current_dataset.dxl = np.delete(self.current_dataset.dxl, [0])
-                self.current_dataset.dxl = self.current_dataset.dxl.astype(np.float64)
-            if self.current_dataset.dxw is not None:
-                self.current_dataset.dxw = np.delete(self.current_dataset.dxw, [0])
-                self.current_dataset.dxw = self.current_dataset.dxw.astype(np.float64)
-            if self.current_dataset.dy is not None:
-                self.current_dataset.dy = np.delete(self.current_dataset.dy, [0])
-                self.current_dataset.dy =self.current_dataset.dy.astype(np.float64)
-
-        if len(self.current_dataset.trans_spectrum) is not 0:
+        Does some final cleanup and formatting on self.current_datainfo and all data1D and data2D objects and then
+        combines the data and info into Data1D and Data2D objects
+        """
+
+        ## Type cast data arrays to float64
+        if len(self.current_datainfo.trans_spectrum) > 0:
             spectrum_list = []
-            for spectrum in self.current_dataset.trans_spectrum:
+            for spectrum in self.current_datainfo.trans_spectrum:
                 spectrum.transmission = np.delete(spectrum.transmission, [0])
                 spectrum.transmission = spectrum.transmission.astype(np.float64)
@@ -346,18 +285,80 @@
                 spectrum.wavelength = np.delete(spectrum.wavelength, [0])
                 spectrum.wavelength = spectrum.wavelength.astype(np.float64)
-                spectrum_list.append(spectrum)
-            self.current_dataset.trans_spectrum = spectrum_list
-
-        else:
-            self.errors.add("ShouldNeverHappenException")
-
-        ## Append intermediate objects to data
-        self.current_dataset.sample = self.sample
-        self.current_dataset.source = self.source
-        self.current_dataset.collimation.append(self.collimation)
+                if len(spectrum.transmission) > 0:
+                    spectrum_list.append(spectrum)
+            self.current_datainfo.trans_spectrum = spectrum_list
 
         ## Append errors to dataset and reset class errors
-        self.current_dataset.errors = self.errors
+        self.current_datainfo.errors = self.errors
         self.errors.clear()
+
+        ## Combine all plottables with datainfo and append each to output
+        ## Type cast data arrays to float64 and find min/max as appropriate
+        for dataset in self.data2d:
+            dataset.data = np.delete(dataset.data, [0])
+            dataset.data = dataset.data.astype(np.float64)
+            dataset.err_data = np.delete(dataset.err_data, [0])
+            dataset.err_data = dataset.err_data.astype(np.float64)
+            dataset.mask = np.delete(dataset.mask, [0])
+            if dataset.qx_data is not None:
+                dataset.qx_data = np.delete(dataset.qx_data, [0])
+                dataset.xmin = np.min(dataset.qx_data)
+                dataset.xmax = np.max(dataset.qx_data)
+                dataset.qx_data = dataset.qx_data.astype(np.float64)
+            if dataset.dqx_data is not None:
+                dataset.dqx_data = np.delete(dataset.dqx_data, [0])
+                dataset.dqx_data = dataset.dqx_data.astype(np.float64)
+            if dataset.qy_data is not None:
+                dataset.qy_data = np.delete(dataset.qy_data, [0])
+                dataset.ymin = np.min(dataset.qy_data)
+                dataset.ymax = np.max(dataset.qy_data)
+                dataset.qy_data = dataset.qy_data.astype(np.float64)
+            if dataset.dqy_data is not None:
+                dataset.dqy_data = np.delete(dataset.dqy_data, [0])
+                dataset.dqy_data = dataset.dqy_data.astype(np.float64)
+            if dataset.q_data is not None:
+                dataset.q_data = np.delete(dataset.q_data, [0])
+                dataset.q_data = dataset.q_data.astype(np.float64)
+            zeros = np.ones(dataset.data.size, dtype=bool)
+            try:
+                for i in range (0, dataset.mask.size - 1):
+                    zeros[i] = dataset.mask[i]
+            except:
+                self.errors.add(sys.exc_value)
+            dataset.mask = zeros
+            ## Calculate the actual Q matrix
+            try:
+                if dataset.q_data.size <= 1:
+                    dataset.q_data = np.sqrt(dataset.qx_data * dataset.qx_data + dataset.qy_data * dataset.qy_data)
+            except:
+                dataset.q_data = None
+            final_dataset = combine_data_info_with_plottable(dataset, self.current_datainfo)
+            self.output.append(final_dataset)
+
+        for dataset in self.data1d:
+            if dataset.x is not None:
+                dataset.x = np.delete(dataset.x, [0])
+                dataset.x = dataset.x.astype(np.float64)
+                dataset.xmin = np.min(dataset.x)
+                dataset.xmax = np.max(dataset.x)
+            if dataset.y is not None:
+                dataset.y = np.delete(dataset.y, [0])
+                dataset.y = dataset.y.astype(np.float64)
+                dataset.ymin = np.min(dataset.y)
+                dataset.ymax = np.max(dataset.y)
+            if dataset.dx is not None:
+                dataset.dx = np.delete(dataset.dx, [0])
+                dataset.dx = dataset.dx.astype(np.float64)
+            if dataset.dxl is not None:
+                dataset.dxl = np.delete(dataset.dxl, [0])
+                dataset.dxl = dataset.dxl.astype(np.float64)
+            if dataset.dxw is not None:
+                dataset.dxw = np.delete(dataset.dxw, [0])
+                dataset.dxw = dataset.dxw.astype(np.float64)
+            if dataset.dy is not None:
+                dataset.dy = np.delete(dataset.dy, [0])
+                dataset.dy = dataset.dy.astype(np.float64)
+            final_dataset = combine_data_info_with_plottable(dataset, self.current_datainfo)
+            self.output.append(final_dataset)
 
     def add_data_set(self, key=""):
@@ -367,46 +368,48 @@
 
         :param key: NeXus group name for current tree level
-        :return: None
-        """
-        if self.current_dataset is not None:
+        """
+
+        if self.current_datainfo and self.current_dataset:
             self.final_data_cleanup()
-            self.output.append(self.current_dataset)
-        self._initialize_new_data_set(key)
-
-    def _initialize_new_data_set(self, key=""):
+        self.data1d = []
+        self.data2d = []
+        self.current_datainfo = DataInfo()
+
+    def _initialize_new_data_set(self, parent_list = None):
         """
         A private class method to generate a new 1D or 2D data object based on the type of data within the set.
         Outside methods should call add_data_set() to be sure any existing data is stored properly.
 
-        :param key: NeXus group name for current tree level
-        :return: None
-        """
-        entry = self._find_intermediate(key, "sasentry*")
-        data = entry.get("sasdata")
-        if data.get("Qx") is not None:
-            self.current_dataset = Data2D()
+        :param parent_list: List of names of parent elements
+        """
+
+        if parent_list is None:
+            parent_list = []
+        if self._find_intermediate(parent_list, "Qx"):
+            self.current_dataset = plottable_2D()
         else:
             x = np.array(0)
             y = np.array(0)
-            self.current_dataset = Data1D(x, y)
-        self.current_dataset.filename = self.raw_data.filename
-
-    def _find_intermediate(self, key="", basename=""):
+            self.current_dataset = plottable_1D(x, y)
+        self.current_datainfo.filename = self.raw_data.filename
+
+    def _find_intermediate(self, parent_list, basename=""):
         """
         A private class used to find an entry by either using a direct key or knowing the approximate basename.
 
-        :param key: Exact keyname of an entry
-        :param basename: Approximate name of an entry
+        :param parent_list: List of parents to the current level in the HDF5 file
+        :param basename: Approximate name of an entry to search for
         :return:
         """
-        entry = []
-        if key is not "":
-            entry = self.raw_data.get(key)
-        else:
-            key_prog = re.compile(basename)
-            for key in self.raw_data.keys():
-                if (key_prog.match(key)):
-                    entry = self.raw_data.get(key)
-                    break
+
+        entry = False
+        key_prog = re.compile(basename)
+        top = self.raw_data
+        for parent in parent_list:
+            top = top.get(parent)
+        for key in top.keys():
+            if (key_prog.match(key)):
+                entry = True
+                break
         return entry
 
@@ -419,4 +422,5 @@
         :param name: The index of the item to be added to dictionary
         :param numb: The number to be appended to the name, starts at 0
+        :return: The new name for the dictionary entry
         """
         if dictionary.get(name) is not None:
@@ -432,10 +436,9 @@
 
         :param value: attribute dictionary for a particular value set
-        :return:
+        :return: unit for the value passed to the method
         """
         unit = value.attrs.get(u'units')
         if unit == None:
             unit = value.attrs.get(u'unit')
-
         ## Convert the unit formats
         if unit == "1/A":
@@ -443,4 +446,3 @@
         elif unit == "1/cm":
             unit = "cm^{-1}"
-
         return unit
Index: src/sas/sascalc/dataloader/readers/schema/cansas1d_invalid.xsd
===================================================================
--- src/sas/sascalc/dataloader/readers/schema/cansas1d_invalid.xsd	(revision 83b6408fbfaefa4819b955c697fef834d8f033f6)
+++ src/sas/sascalc/dataloader/readers/schema/cansas1d_invalid.xsd	(revision 83b6408fbfaefa4819b955c697fef834d8f033f6)
@@ -0,0 +1,269 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="xsd-documentation.xsl" ?>
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+	xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+	xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"  jaxb:version="2.0"
+	targetNamespace="urn:cansas1d:1.1" xmlns:tns="urn:cansas1d:1.1"
+	elementFormDefault="qualified">
+
+<!-- 
+Copyright (c) 2013, UChicago Argonne, LLC
+This file is distributed subject to a Software License Agreement found
+in the file LICENSE that is included with this distribution. 
+ -->
+ 
+<!-- JAXB: http://java.sun.com/developer/technicalArticles/WebServices/jaxb/ -->
+
+	<complexType name="floatUnitType">
+		<simpleContent>
+			<extension base="float">
+				<attribute name="unit" type="string" use="required" />
+			</extension>
+		</simpleContent>
+	</complexType>
+
+	<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+	<group name="positionGroup">
+		<sequence>
+			<element name="x" type="tns:floatUnitType" minOccurs="0" maxOccurs="1" />
+			<element name="y" type="tns:floatUnitType" minOccurs="0" maxOccurs="1" />
+			<element name="z" type="tns:floatUnitType" minOccurs="0" maxOccurs="1" />
+		</sequence>
+	</group>
+
+	<complexType name="positionType">
+		<group ref="tns:positionGroup" />
+		<attribute name="name" type="string" use="optional" default="" />
+	</complexType>
+
+	<group name="orientationGroup">
+		<sequence>
+			<element name="roll" type="tns:floatUnitType" minOccurs="0"  maxOccurs="1" />
+			<element name="pitch" type="tns:floatUnitType" minOccurs="0" maxOccurs="1" />
+			<element name="yaw" type="tns:floatUnitType" minOccurs="0"   maxOccurs="1" />
+		</sequence>
+	</group>
+
+	<complexType name="orientationType">
+		<group ref="tns:orientationGroup" />
+		<attribute name="name" type="string" use="optional" default="" />
+	</complexType>
+
+	<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+	
+	<complexType name="IdataType">
+		<sequence>
+			<element name="Q" minOccurs="1" maxOccurs="1"    type="tns:floatUnitType" />
+			<element name="I" minOccurs="1" maxOccurs="1"    type="tns:floatUnitType" />
+			<element name="Idev" minOccurs="0" maxOccurs="1" type="tns:floatUnitType" default="0" />
+			<xsd:choice>
+				<!-- [ [Qdev] | [[dQw] | [dQl]] ] -->
+				<element name="Qdev" minOccurs="0" maxOccurs="1" type="tns:floatUnitType" default="0" />
+				<xsd:sequence>
+					<element name="dQw" minOccurs="0" maxOccurs="1" type="tns:floatUnitType" default="0" />
+					<element name="dQl" minOccurs="0" maxOccurs="1" type="tns:floatUnitType" default="0" />
+				</xsd:sequence>
+			</xsd:choice>
+			<element name="Qmean" minOccurs="0" maxOccurs="1" type="tns:floatUnitType" default="0" />
+			<element name="Shadowfactor" minOccurs="0" maxOccurs="1" type="float" default="1.0" />
+			<xsd:any minOccurs="0" maxOccurs="unbounded" processContents="skip" namespace="##other" />
+		</sequence>
+	</complexType>
+	
+	<complexType name="SASdataType">
+		<sequence minOccurs="1" maxOccurs="1">  <!-- http://svn.cansas.org/trac/ticket/21 -->
+			<sequence>
+				<element name="Idata" minOccurs="1" maxOccurs="unbounded" type="tns:IdataType" />
+			</sequence>
+			<xsd:any minOccurs="0" maxOccurs="unbounded" processContents="skip" namespace="##other" />
+		</sequence>
+		<attribute name="name" type="string" use="optional" default="" />
+		<attribute name="timestamp" type="dateTime" use="optional" />
+	</complexType>
+	
+	<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+	
+	<complexType name="TdataType">
+			<sequence>
+				<element name="Lambda" minOccurs="0" maxOccurs="1"    type="tns:floatUnitType" />
+				<element name="T" minOccurs="0" maxOccurs="1"    type="tns:floatUnitType" />
+				<element name="Tdev" minOccurs="0" maxOccurs="1" type="tns:floatUnitType" default="0" />
+				<xsd:any minOccurs="0" maxOccurs="unbounded" processContents="skip" namespace="##other" />
+		</sequence>
+	</complexType>
+	
+	<complexType name="SAStransmission_spectrumType">
+		<sequence minOccurs="0" maxOccurs="1">
+			<sequence minOccurs="0" maxOccurs="1">
+				<element name="Tdata" minOccurs="0" maxOccurs="unbounded" type="tns:TdataType" />
+			</sequence>
+			<xsd:any minOccurs="0" maxOccurs="unbounded" processContents="skip" namespace="##other" />
+		</sequence>
+		<attribute name="name" type="string" use="optional" default="" />
+		<attribute name="timestamp" type="dateTime" use="optional" />
+	</complexType>
+	
+	<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+	<complexType name="SASsampleType">
+		<sequence>
+			<element name="ID" minOccurs="0" maxOccurs="1" type="string" />
+			<element name="thickness" minOccurs="0" maxOccurs="1" type="tns:floatUnitType" />
+			<element name="transmission" minOccurs="0" maxOccurs="1" type="float" />
+			<element name="temperature" minOccurs="0" maxOccurs="1" type="tns:floatUnitType" />
+			<element name="position" minOccurs="0" maxOccurs="1" type="tns:positionType" />
+			<element name="orientation" minOccurs="0" maxOccurs="1" type="tns:orientationType" />
+			<element name="details" minOccurs="0" maxOccurs="unbounded" />
+			<xsd:any minOccurs="0" maxOccurs="unbounded" processContents="skip" namespace="##other" />
+		</sequence>
+		<attribute name="name" type="string" use="optional" default="" />
+	</complexType>
+
+	<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+	<complexType name="termType">
+		<simpleContent>
+			<extension base="string">
+				<attribute name="name" type="string" use="optional" default="" />
+				<attribute name="unit" type="string" use="optional"/>
+			</extension>
+		</simpleContent>
+	</complexType>
+
+	<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+	<complexType name="SASprocessType">
+		<annotation>
+			<appinfo>
+				<!-- JAXB: simplify class name -->
+				<jaxb:property name="SASprocess" />
+			</appinfo>
+		</annotation>
+		<sequence>
+			<element name="name" minOccurs="0" maxOccurs="1" type="string" default="">
+				<annotation>
+					<appinfo>
+						<!-- Remap collision of Name when using JAXB -->
+						<jaxb:property name="SASprocessName" />
+					</appinfo>
+				</annotation>
+			</element>
+			<element name="date" minOccurs="0" maxOccurs="1" type="string" />
+			<element name="description" minOccurs="0" maxOccurs="1" />
+			<element name="term" minOccurs="0" maxOccurs="unbounded" type="tns:termType" />
+			<element name="SASprocessnote" minOccurs="0" maxOccurs="unbounded" />
+			<xsd:any minOccurs="0" maxOccurs="unbounded" processContents="skip" namespace="##other" />
+		</sequence>
+		<attribute name="name" type="string" use="optional" default="">
+			<annotation>
+				<appinfo>
+					<!-- Remap collision of Name when using JAXB -->
+					<jaxb:property name="SASprocessNameAttr" />
+				</appinfo>
+			</annotation>
+		</attribute>
+	</complexType>
+
+	<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+	<complexType name="SASsourceType">
+		<sequence>
+			<element name="radiation" minOccurs="0" maxOccurs="1" type="string" />
+			<element name="beam_size" minOccurs="0" maxOccurs="1" type="tns:positionType" />
+			<element name="beam_shape" minOccurs="0" maxOccurs="1" type="string" />
+			<element name="wavelength" minOccurs="0" maxOccurs="1" type="tns:floatUnitType" />
+			<element name="wavelength_min" minOccurs="0" maxOccurs="1" type="tns:floatUnitType" />
+			<element name="wavelength_max" minOccurs="0" maxOccurs="1" type="tns:floatUnitType" />
+			<element name="wavelength_spread" minOccurs="0" maxOccurs="1" type="tns:floatUnitType" />
+		</sequence>
+		<attribute name="name" type="string" use="optional" default="" />
+	</complexType>
+
+	<complexType name="SAScollimationType">
+		<sequence>
+			<element name="length" minOccurs="0" maxOccurs="1" type="tns:floatUnitType" />
+			<element name="aperture" minOccurs="0" maxOccurs="unbounded">
+				<complexType>
+					<sequence>
+						<element name="size" minOccurs="0" maxOccurs="1" type="tns:positionType" />
+						<element name="distance" minOccurs="0" maxOccurs="1" type="tns:floatUnitType" />
+					</sequence>
+					<attribute name="name" type="string" use="optional" default="" />
+					<attribute name="type" type="string" use="optional" default="" />
+				</complexType>
+			</element>
+		</sequence>
+		<attribute name="name" type="string" use="optional" default="" />
+	</complexType>
+
+	<complexType name="SASdetectorType">
+		<sequence>
+			<element name="name" minOccurs="0" maxOccurs="1" type="string" default=""/>
+			<element name="SDD" minOccurs="0" maxOccurs="1" type="tns:floatUnitType" />
+			<element name="offset" minOccurs="0" maxOccurs="1" type="tns:positionType" />
+			<element name="orientation" minOccurs="0" maxOccurs="1" type="tns:orientationType" />
+			<element name="beam_center" minOccurs="0" maxOccurs="1" type="tns:positionType" />
+			<element name="pixel_size" minOccurs="0" maxOccurs="1" type="tns:positionType" />
+			<element name="slit_length" minOccurs="0" maxOccurs="1" type="tns:floatUnitType" />
+		</sequence>
+	</complexType>
+
+	<complexType name="SASinstrumentType">
+		<sequence>
+			<element name="name" type="string" minOccurs="0" maxOccurs="1" default="" />
+			<element name="SASsource" type="tns:SASsourceType" minOccurs="0" maxOccurs="1" />
+			<element name="SAScollimation" type="tns:SAScollimationType" minOccurs="0" maxOccurs="unbounded" />
+			<element name="SASdetector" type="tns:SASdetectorType" minOccurs="0" maxOccurs="unbounded" />
+		</sequence>
+	</complexType>
+
+	<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+	<complexType name="SASentryType">
+		<sequence>
+			<element name="Title" minOccurs="0" maxOccurs="1" type="string" />
+			<element name="Run" minOccurs="0" maxOccurs="unbounded">
+				<xsd:complexType>
+					<simpleContent>
+						<extension base="string">
+							<attribute name="name" type="string" use="optional" default="" />
+						</extension>
+					</simpleContent>
+				</xsd:complexType>
+			</element>
+			<xsd:any minOccurs="0" maxOccurs="unbounded" processContents="skip" namespace="##other" />
+			<element name="SASdata" minOccurs="1" maxOccurs="unbounded" type="tns:SASdataType" />
+			<element name="SAStransmission_spectrum" minOccurs="0" maxOccurs="unbounded" type="tns:SAStransmission_spectrumType"/>
+			<xsd:any minOccurs="0" maxOccurs="unbounded" processContents="skip" namespace="##other">
+				<!-- Is a second *any* element needed here? -->
+				<annotation>
+					<appinfo>
+						<!-- Remap collision of Any when using JAXB --> 
+						<jaxb:property name="SASentryAny2" />
+					</appinfo>
+				</annotation>
+			</xsd:any>
+			<element name="SASsample" type="tns:SASsampleType" />
+			<element name="SASinstrument" type="tns:SASinstrumentType" minOccurs="0" maxOccurs="1" />
+			<element name="SASprocess" type="tns:SASprocessType" minOccurs="0" maxOccurs="unbounded" />
+			<element name="SASnote" minOccurs="0" maxOccurs="unbounded" />
+				<!-- SASnote is a free-form element.
+					Do not define any content for it or it will become restrictive.
+				-->
+		</sequence>
+		<attribute name="name" type="string" use="optional" default="" />
+	</complexType>
+
+	<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+	<complexType name="SASrootType">
+		<sequence>
+			<element name="SASentry" minOccurs="1" maxOccurs="unbounded" type="tns:SASentryType" />
+		</sequence>
+		<attribute name="version" type="string" fixed="1.1" use="optional" />
+	</complexType>
+
+	<element name="SASroot" type="tns:SASrootType" />
+
+</schema>
