source: sasview/src/sans/dataloader/readers/xml_reader.py @ eacf6a8c

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since eacf6a8c was ea67541, checked in by Jeff Krzywon <jeffery.krzywon@…>, 11 years ago

Fix for ticket #204 - processing instructions were not being set properly when saving as cansas data file.

  • Property mode set to 100644
File size: 4.9 KB
Line 
1"""
2    Generic XML reader
3"""
4############################################################################
5#This software was developed by the University of Tennessee as part of the
6#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
7#project funded by the US National Science Foundation.
8#If you use DANSE applications to do scientific research that leads to
9#publication, we ask that you acknowledge the use of the software with the
10#following sentence:
11#This work benefited from DANSE software developed under NSF award DMR-0520547.
12#copyright 2008,2009 University of Tennessee
13#############################################################################
14
15from lxml import etree
16parser = etree.ETCompatXMLParser(remove_comments=True, remove_pis=False)
17
18class XMLreader():
19   
20    xml = None
21    xmldoc = None
22    xmlroot = None
23    schema = None
24    schemadoc = None
25    processingInstructions = None
26   
27    def __init__(self, xml = None, schema = None, root = None):
28        self.xml = xml
29        self.schema = schema
30        self.processingInstructions = {}
31        if xml is not None:
32            self.setXMLFile(xml, root)
33        else:
34            self.xmldoc = None
35            self.xmlroot = None
36        if schema is not None:
37            self.setSchema(schema)
38        else:
39            self.schemadoc = None
40   
41    def reader(self):
42        """
43        Read in an XML file into memory and return an lxml dictionary
44        """
45        if self.validateXML():
46            self.xmldoc = etree.parse(self.xml, parser = parser)
47        else:
48            raise etree.ValidationError(self, self.findInvalidXML())
49        return self.xmldoc
50   
51    def setXMLFile(self, xml, root = None):
52        """
53        Set the XML file and parse
54        """
55        try:
56            self.xml = xml
57            self.xmldoc = etree.parse(self.xml, parser = parser)
58            self.xmlroot = self.xmldoc.getroot()
59        except Exception:
60            self.xml = None
61            self.xmldoc = None
62            self.xmlroot = None
63   
64    def setSchema(self, schema):
65        """
66        Set the schema file and parse
67        """
68        try:
69            self.schema = schema
70            self.schemadoc = etree.parse(self.schema, parser = parser)
71        except Exception:
72            self.schema = None
73            self.schemadoc = None
74   
75    def validateXML(self):
76        """
77        Checks to see if the XML file meets the schema
78        """
79        valid = True
80        if self.schema is not None:
81            self.parseSchemaAndDoc()
82            schemaCheck = etree.XMLSchema(self.schemadoc)
83            valid = schemaCheck.validate(self.xmldoc)
84        return valid
85   
86    def findInvalidXML(self):
87        """
88        Finds the first offending element that should not be present in XML file
89        """
90        firstError = ""
91        self.parseSchemaAndDoc()
92        schema = etree.XMLSchema(self.schemadoc)
93        try:
94            firstError = schema.assertValid(self.xmldoc)
95        except etree.DocumentInvalid as e:
96            firstError = str(e)
97        return firstError
98   
99    def parseSchemaAndDoc(self):
100        """
101        Creates a dictionary of the parsed schema and xml files.
102        """
103        self.setXMLFile(self.xml)
104        self.setSchema(self.schema)
105       
106    def toString(self, etreeElement):
107        """
108        Converts and etree element into a string
109        """
110        return etree.tostring(etreeElement)
111   
112    def setProcessingInstructions(self):
113        """
114        Take out all processing instructions and create a dictionary from them
115        """
116        dic = {}
117        pi = self.xmlroot.getprevious()
118        while pi is not None:
119            attr = {}
120            pi_name = ""
121            pi_string = self.toString(pi)
122            if isinstance(pi_string, str):
123                pi_string = pi_string.replace("<?", "").replace("?>", "")
124                split = pi_string.split(" ", 1)
125                pi_name = split[0]
126                attr = split[1]
127            new_pi_name = self._create_unique_key(dic, pi_name)
128            dic[new_pi_name] = attr
129            pi = pi.getprevious()
130        self.processingInstructions = dic
131       
132    def _create_unique_key(self, dictionary, name, i = 0):
133        """
134        Create a unique key value for any dictionary to prevent overwriting
135        Recurses until a unique key value is found.
136       
137        :param dictionary: A dictionary with any number of entries
138        :param name: The index of the item to be added to dictionary
139        :param i: The number to be appended to the name, starts at 0
140        """
141        if dictionary.get(name) is not None:
142            i += 1
143            name = name.split("_")[0]
144            name += "_{0}".format(i)
145            name = self._create_unique_key(dictionary, name, i)
146        return name
147   
148       
Note: See TracBrowser for help on using the repository browser.