3 # Copyright (C) 2010-2013 CEA/DEN
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.
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.
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
25 sys.setdefaultencoding('utf8')
30 import src.ElementTree as etree
34 class XmlLogFile(object):
35 '''Class to manage writing in salomeTools xml log file
37 def __init__(self, filePath, rootname, attrib = {}):
40 :param filePath str: The path to the file where to write the log file
41 :param rootname str: The name of the root node of the xml file
42 :param attrib dict: the dictionary that contains the attributes
43 and value of the root node
45 # Initialize the filePath and ensure that the directory
46 # that contain the file exists (make it if necessary)
47 self.logFile = filePath
48 src.ensure_path_exists(os.path.dirname(filePath))
49 # Initialize the field that contain the xml in memory
50 self.xmlroot = etree.Element(rootname, attrib = attrib)
52 def write_tree(self, stylesheet=None, file_path = None):
53 '''Write the xml tree in the log file path. Add the stylesheet if asked.
55 :param stylesheet str: The stylesheet to apply to the xml file
57 log_file_path = self.logFile
59 log_file_path = file_path
61 with open(log_file_path, 'w') as f:
62 f.write("<?xml version='1.0' encoding='utf-8'?>\n")
64 # example as href='./hat.xsl'
65 # as local file xml with local file xsl
66 # with 'python3 -m http.server 8765 &' and
67 # 'chromium-browser http://localhost:8765/hat.xml' or
68 # 'firefox http://localhost:8765/hat.xml'
69 f.write("<?xml-stylesheet type='text/xsl' href='./%s'?>\n" % stylesheet)
71 res= etree.tostring(self.xmlroot, encoding='utf-8')
76 def add_simple_node(self, node_name, text=None, attrib={}):
77 '''Add a node with some attibutes and text to the root node.
79 :param node_name str: the name of the node to add
80 :param text str: the text of the node
81 :param attrib dict: the dictionary containing the
82 attribute of the new node
84 n = etree.Element(node_name, attrib=attrib)
86 self.xmlroot.append(n)
89 def append_node_text(self, node_name, text):
90 '''Append a new text to the node that has node_name as name
92 :param node_name str: The name of the node on which append text
93 :param text str: The text to append
95 # find the corresponding node
96 for field in self.xmlroot:
97 if field.tag == node_name:
101 def append_node_attrib(self, node_name, attrib):
102 '''Append a new attributes to the node that has node_name as name
104 :param node_name str: The name of the node on which append text
105 :param attrib dixt: The attrib to append
107 self.xmlroot.find(node_name).attrib.update(attrib)
109 class ReadXmlFile(object):
110 '''Class to manage reading of an xml log file
112 def __init__(self, filePath):
115 :param filePath str: The xml file to be read
117 self.filePath = filePath
118 etree_inst = etree.parse(filePath)
119 self.xmlroot = etree_inst.parse(filePath)
121 def getRootAttrib(self):
122 '''Get the attibutes of the self.xmlroot
124 :return: The attributes of the root node
127 return self.xmlroot.attrib
129 def get_attrib(self, node_name):
130 '''Get the attibutes of the node node_name in self.xmlroot
132 :param node_name str: the name of the node
133 :return: the attibutes of the node node_name in self.xmlroot
136 attrib = self.xmlroot.find(node_name).attrib
137 # To be python 3 compatible, convert bytes to str if there are any
139 for k in attrib.keys():
140 if isinstance(k, bytes):
144 if isinstance(attrib[k], bytes):
145 value = attrib[k].decode()
148 fixedAttrib[key] = value
151 def get_node_text(self, node):
152 '''Get the text of the first node that has name
153 that corresponds to the parameter node
155 :param node str: the name of the node from which get the text
156 :return: the text of the first node that has name
157 that corresponds to the parameter node
160 return self.xmlroot.find(node).text
162 def add_simple_node(root_node, node_name, text=None, attrib={}):
163 '''Add a node with some attibutes and text to the root node.
165 :param root_node etree.Element: the Etree element where to add the new node
166 :param node_name str: the name of the node to add
167 :param text str: the text of the node
168 :param attrib dict: the dictionary containing the
169 attribute of the new node
171 n = etree.Element(node_name, attrib=attrib)
176 def append_node_attrib(root_node, attrib):
177 '''Append a new attributes to the node that has node_name as name
179 :param root_node etree.Element: the Etree element
180 where to append the new attibutes
181 :param attrib dixt: The attrib to append
183 root_node.attrib.update(attrib)
185 def find_node_by_attrib(xmlroot, name_node, key, value):
186 '''Find the nfirst ode from xmlroot that has name name_node and that has in
187 its attributes {key : value}. Return the node
189 :param xmlroot etree.Element: the Etree element where to search
190 :param name_node str: the name of node to search
191 :param key str: the key to search
192 :param value str: the value to search
193 :return: the found node
194 :rtype: xmlroot etree.Element
196 l_nodes = xmlroot.findall(name_node)
198 if key not in node.attrib.keys():
200 if node.attrib[key] == value:
205 def write_report(filename, xmlroot, stylesheet):
206 """Writes a report file from a XML tree.
208 :param filename str: The path to the file to create
209 :param xmlroot etree.Element: the Etree element to write to the file
210 :param stylesheet str: The stylesheet to add to the begin of the file
212 dirname = os.path.dirname(filename)
213 if not os.path.exists(dirname):
215 if len(stylesheet) > 0:
216 styleName = stylesheet
220 with open(filename, "w") as f:
221 f.write("<?xml version='1.0' encoding='utf-8'?>\n")
222 if styleName is not None:
223 f.write("<?xml-stylesheet type='text/xsl' href='%s'?>\n" % styleName)
224 res = etree.tostring(xmlroot, encoding='utf-8')
225 # print("********** etree.tostring %s" % res)
228 # create fileStyle in dirname if not existing
229 if styleName is not None:
230 styleFile = os.path.join(dirname, styleName)
231 if not os.path.exists(styleFile):
232 # copy if from "salomeTools/src/xsl"
233 srcdir = os.path.dirname(src.__file__)
234 srcFile = os.path.join(srcdir, "xsl", styleName)
235 if verbose: print("write_report %s style %s" % (srcFile, styleFile))
236 shutil.copy(srcFile, dirname)
238 def escapeSequence(aStr):
240 See xml specification:
241 The ampersand character(&) and the left angle bracket(<) MUST NOT appear in their
242 literal form, except when used as markup delimiters, or within a comment, a processing
243 instruction, or a CDATA section.
244 If they are needed elsewhere, they MUST be escaped using either numeric character references
245 or the strings '&' and '<' respectively.
246 The right angle bracket(>) may be
247 represented using the string '>', and MUST,
248 for compatibility, be escaped using either '>' or a character reference
249 when it appears in the string " ]]> " in content,
250 when that string is not marking the end of a CDATA section.
251 You can use these escape sequences:
252 < (less - than) as < or <
253 > (greater - than) as > or >
254 & (ampersand) as &
255 ' (apostrophe or single quote) as '
256 " (double-quote) as "
258 replaces = [ ('&', '&'),
265 for ini, fin in replaces: # order matters
266 res = res.replace(ini, fin)