Salome HOME
merge from master 8B7B
[tools/sat.git] / src / xmlManager.py
1 #!/usr/bin/env python
2 #-*- coding:utf-8 -*-
3 #  Copyright (C) 2010-2013  CEA/DEN
4 #
5 #  This library is free software; you can redistribute it and/or
6 #  modify it under the terms of the GNU Lesser General Public
7 #  License as published by the Free Software Foundation; either
8 #  version 2.1 of the License.
9 #
10 #  This library is distributed in the hope that it will be useful,
11 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 #  Lesser General Public License for more details.
14 #
15 #  You should have received a copy of the GNU Lesser General Public
16 #  License along with this library; if not, write to the Free Software
17 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18
19 import os
20 try: # For python2
21     import sys
22     reload(sys)  
23     sys.setdefaultencoding('utf8')
24 except:
25     pass
26
27 import src
28 from . import ElementTree as etree
29
30 class XmlLogFile(object):
31     '''Class to manage writing in salomeTools xml log file
32     '''
33     def __init__(self, filePath, rootname, attrib = {}):
34         '''Initialization
35         
36         :param filePath str: The path to the file where to write the log file
37         :param rootname str: The name of the root node of the xml file
38         :param attrib dict: the dictionary that contains the attributes 
39                             and value of the root node
40         '''
41         # Initialize the filePath and ensure that the directory 
42         # that contain the file exists (make it if necessary)
43         self.logFile = filePath
44         src.ensure_path_exists(os.path.dirname(filePath))
45         # Initialize the field that contain the xml in memory
46         self.xmlroot = etree.Element(rootname, attrib = attrib)
47
48     def escapeSequence(self, aStr):
49         """
50         See xml specification:
51         The ampersand character(&) and the left angle bracket(<) MUST NOT appear in their
52         literal form, except when used as markup delimiters, or within a comment, a processing
53         instruction, or a CDATA section.
54         If they are needed elsewhere, they MUST be escaped using either numeric character references
55         or the strings '&amp;' and '&lt;' respectively.
56         The right angle bracket(>) may be
57         represented using the string '&gt;', and MUST,
58         for compatibility, be escaped using either '&gt;' or a character reference
59         when it appears in the string " ]]> " in content,
60         when that string is not marking the end of a CDATA section.
61         You can use these escape sequences:
62         < (less - than) as &#60; or &lt;
63         > (greater - than) as &#62; or &gt;
64         & (ampersand) as &#38;
65         ' (apostrophe or single quote) as &#39;
66         " (double-quote) as &#34;
67         """
68         replaces = [ ('&', '&amp;'),
69                      ('>', '&gt;'),
70                      ('<', '&lt;'),
71                      ("'", '&#39;'),
72                      ('"', '&#34;'),
73                     ]
74         res = aStr
75         for ini, fin in replaces: # order matters
76           res = res.replace(ini, fin)
77         return res
78
79
80 def write_tree(self, stylesheet=None, file_path = None):
81         '''Write the xml tree in the log file path. Add the stylesheet if asked.
82         
83         :param stylesheet str: The stylesheet to apply to the xml file
84         '''
85         log_file_path = self.logFile
86         if file_path:
87             log_file_path = file_path
88         try:
89             f = open(log_file_path, 'w')
90             f.write("<?xml version='1.0' encoding='utf-8'?>\n")
91             if stylesheet:
92                 f.write("<?xml-stylesheet type='text/xsl' href='%s'?>\n" % 
93                         stylesheet)    
94             f.write(etree.tostring(self.xmlroot, encoding='utf-8'))
95             f.close()
96         except IOError:
97             pass  
98         
99     def add_simple_node(self, node_name, text=None, attrib={}):
100         '''Add a node with some attibutes and text to the root node.
101         
102         :param node_name str: the name of the node to add
103         :param text str: the text of the node
104         :param attrib dict: the dictionary containing the 
105                             attribute of the new node
106         '''
107         n = etree.Element(node_name, attrib=attrib)
108         n.text = text
109         self.xmlroot.append(n)
110         return n
111     
112     def append_node_text(self, node_name, text):
113         '''Append a new text to the node that has node_name as name
114         
115         :param node_name str: The name of the node on which append text
116         :param text str: The text to append
117         '''
118         # find the corresponding node
119         for field in self.xmlroot:
120             if field.tag == node_name:
121                 # append the text
122                 field.text += text
123
124     def append_node_attrib(self, node_name, attrib):
125         '''Append a new attributes to the node that has node_name as name
126         
127         :param node_name str: The name of the node on which append text
128         :param attrib dixt: The attrib to append
129         '''
130         self.xmlroot.find(node_name).attrib.update(attrib)
131
132 class ReadXmlFile(object):
133     '''Class to manage reading of an xml log file
134     '''
135     def __init__(self, filePath):
136         '''Initialization
137         
138         :param filePath str: The xml file to be read
139         '''
140         self.filePath = filePath
141         etree_inst = etree.parse(filePath)
142         self.xmlroot = etree_inst.parse(filePath)
143
144     def getRootAttrib(self):
145         '''Get the attibutes of the self.xmlroot
146         
147         :return: The attributes of the root node
148         :rtype: dict
149         '''
150         return self.xmlroot.attrib
151     
152     def get_attrib(self, node_name):
153         '''Get the attibutes of the node node_name in self.xmlroot
154         
155         :param node_name str: the name of the node
156         :return: the attibutes of the node node_name in self.xmlroot
157         :rtype: dict
158         '''
159         attrib = self.xmlroot.find(node_name).attrib
160         # To be python 3 compatible, convert bytes to str if there are any
161         fixedAttrib = {}
162         for k in attrib.keys():
163             if isinstance(k, bytes):
164                 key = k.decode()
165             else:
166                 key = k
167             if isinstance(attrib[k], bytes):
168                 value = attrib[k].decode()
169             else:
170                 value = attrib[k]
171             fixedAttrib[key] = value
172         return fixedAttrib
173     
174     def get_node_text(self, node):
175         '''Get the text of the first node that has name 
176            that corresponds to the parameter node
177         
178         :param node str: the name of the node from which get the text
179         :return: the text of the first node that has name 
180                  that corresponds to the parameter node
181         :rtype: str
182         '''
183         return self.xmlroot.find(node).text
184     
185 def add_simple_node(root_node, node_name, text=None, attrib={}):
186     '''Add a node with some attibutes and text to the root node.
187
188     :param root_node etree.Element: the Etree element where to add the new node    
189     :param node_name str: the name of the node to add
190     :param text str: the text of the node
191     :param attrib dict: the dictionary containing the 
192                         attribute of the new node
193     '''
194     n = etree.Element(node_name, attrib=attrib)
195     n.text = text
196     root_node.append(n)
197     return n
198
199 def append_node_attrib(root_node, attrib):
200     '''Append a new attributes to the node that has node_name as name
201     
202     :param root_node etree.Element: the Etree element 
203                                     where to append the new attibutes
204     :param attrib dixt: The attrib to append
205     '''
206     root_node.attrib.update(attrib)
207
208 def find_node_by_attrib(xmlroot, name_node, key, value):
209     '''Find the nfirst ode from xmlroot that has name name_node and that has in 
210        its attributes {key : value}. Return the node
211     
212     :param xmlroot etree.Element: the Etree element where to search
213     :param name_node str: the name of node to search
214     :param key str: the key to search
215     :param value str: the value to search
216     :return: the found node
217     :rtype: xmlroot etree.Element
218     '''
219     l_nodes =  xmlroot.findall(name_node)
220     for node in l_nodes:
221         if key not in node.attrib.keys():
222             continue
223         if node.attrib[key] == value:
224             return node
225     return None
226     
227
228 def write_report(filename, xmlroot, stylesheet):
229     """Writes a report file from a XML tree.
230     
231     :param filename str: The path to the file to create
232     :param xmlroot etree.Element: the Etree element to write to the file
233     :param stylesheet str: The stylesheet to add to the begin of the file
234     """
235     if not os.path.exists(os.path.dirname(filename)):
236         os.makedirs(os.path.dirname(filename))
237
238     f = open(filename, "w")
239     f.write("<?xml version='1.0' encoding='utf-8'?>\n")
240     if len(stylesheet) > 0:
241         f.write("<?xml-stylesheet type='text/xsl' href='%s'?>\n" % stylesheet)
242     f.write(etree.tostring(xmlroot, encoding='utf-8'))
243     f.close()   
244