Salome HOME
option compile --update
[tools/sat.git] / src / xmlManager.py
index 7b383c7cf5c870b9670e313f0097edd572d7cd4c..4b4fa61cfc08152cc98c29eb82b9f17756859910 100644 (file)
 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 
 import os
-import re
+import shutil
+
+try: # For python2
+    import sys
+    reload(sys)  
+    sys.setdefaultencoding('utf8')
+except:
+    pass
 
 import src
-from . import ElementTree as etree
+import src.ElementTree as etree
+
+verbose = False
 
-class xmlLogFile(object):
+class XmlLogFile(object):
     '''Class to manage writing in salomeTools xml log file
     '''
     def __init__(self, filePath, rootname, attrib = {}):
@@ -30,32 +39,42 @@ class xmlLogFile(object):
         
         :param filePath str: The path to the file where to write the log file
         :param rootname str: The name of the root node of the xml file
-        :param attrib dict: the dictionary that contains the attributes and value of the root node
+        :param attrib dict: the dictionary that contains the attributes 
+                            and value of the root node
         '''
-        # Initialize the filePath and ensure that the directory that contain the file exists (make it if necessary)
+        # Initialize the filePath and ensure that the directory 
+        # that contain the file exists (make it if necessary)
         self.logFile = filePath
         src.ensure_path_exists(os.path.dirname(filePath))
         # Initialize the field that contain the xml in memory
         self.xmlroot = etree.Element(rootname, attrib = attrib)
-    
-    def write_tree(self, stylesheet=None):
+
+    def write_tree(self, stylesheet=None, file_path = None):
         '''Write the xml tree in the log file path. Add the stylesheet if asked.
         
         :param stylesheet str: The stylesheet to apply to the xml file
         '''
-        f = open(self.logFile, 'w')
-        f.write("<?xml version='1.0' encoding='utf-8'?>\n")
-        if stylesheet:
-            f.write("<?xml-stylesheet type='text/xsl' href='%s'?>\n" % stylesheet)    
-        f.write(etree.tostring(self.xmlroot, encoding='utf-8'))
-        f.close()  
+        log_file_path = self.logFile
+        if file_path:
+          log_file_path = file_path
+        try:
+          with open(log_file_path, 'w') as f:
+            f.write("<?xml version='1.0' encoding='utf-8'?>\n")
+            if stylesheet:
+                f.write("<?xml-stylesheet type='text/xsl' href='%s'?>\n" %  stylesheet)
+                pass
+            res= etree.tostring(self.xmlroot, encoding='utf-8')
+            f.write(res)
+        except IOError:
+            pass  
         
     def add_simple_node(self, node_name, text=None, attrib={}):
         '''Add a node with some attibutes and text to the root node.
         
         :param node_name str: the name of the node to add
         :param text str: the text of the node
-        :param attrib dict: the dictionary containing the attribute of the new node
+        :param attrib dict: the dictionary containing the 
+                            attribute of the new node
         '''
         n = etree.Element(node_name, attrib=attrib)
         n.text = text
@@ -82,7 +101,7 @@ class xmlLogFile(object):
         '''
         self.xmlroot.find(node_name).attrib.update(attrib)
 
-class readXmlFile(object):
+class ReadXmlFile(object):
     '''Class to manage reading of an xml log file
     '''
     def __init__(self, filePath):
@@ -109,81 +128,137 @@ class readXmlFile(object):
         :return: the attibutes of the node node_name in self.xmlroot
         :rtype: dict
         '''
-        return self.xmlroot.find(node_name).attrib
+        attrib = self.xmlroot.find(node_name).attrib
+        # To be python 3 compatible, convert bytes to str if there are any
+        fixedAttrib = {}
+        for k in attrib.keys():
+            if isinstance(k, bytes):
+                key = k.decode()
+            else:
+                key = k
+            if isinstance(attrib[k], bytes):
+                value = attrib[k].decode()
+            else:
+                value = attrib[k]
+            fixedAttrib[key] = value
+        return fixedAttrib
     
     def get_node_text(self, node):
-        '''Get the text of the first node that has name that corresponds to the parameter node
+        '''Get the text of the first node that has name 
+           that corresponds to the parameter node
         
         :param node str: the name of the node from which get the text
-        :return: the text of the first node that has name that corresponds to the parameter node
+        :return: the text of the first node that has name 
+                 that corresponds to the parameter node
         :rtype: str
         '''
-        # Loop on all root nodes
-        for field in self.xmlroot:
-            if field.tag == node:
-                return field.text
-        return ''
-
-def showcommandLog(logFilePath, cmd, application, notShownCommands):
-    '''Used in updateHatXml. Determine if the log xml file logFilePath has to be shown or not in the hat log.
+        return self.xmlroot.find(node).text
     
-    :param logFilePath str: the path to the command xml log file
-    :param cmd str: the command of the log file
-    :param application str: the application passed as parameter to the salomeTools command
-    :param notShownCommands list: the list of commands that are not shown by default
+def add_simple_node(root_node, node_name, text=None, attrib={}):
+    '''Add a node with some attibutes and text to the root node.
+
+    :param root_node etree.Element: the Etree element where to add the new node    
+    :param node_name str: the name of the node to add
+    :param text str: the text of the node
+    :param attrib dict: the dictionary containing the 
+                        attribute of the new node
+    '''
+    n = etree.Element(node_name, attrib=attrib)
+    n.text = text
+    root_node.append(n)
+    return n
+
+def append_node_attrib(root_node, attrib):
+    '''Append a new attributes to the node that has node_name as name
     
-    :return: True if cmd is not in notShownCommands and the application in the log file corresponds to application
-    :rtype: boolean
+    :param root_node etree.Element: the Etree element 
+                                    where to append the new attibutes
+    :param attrib dixt: The attrib to append
     '''
-    # When the command is not in notShownCommands, no need to go further. Do not show
-    if cmd in notShownCommands:
-        return False, None
-    # Get the application of the log file
-    logFileXml = readXmlFile(logFilePath)
-    if 'application' in logFileXml.xmlroot.keys():
-        appliLog = logFileXml.xmlroot.get('application')
-        # if it corresponds, then the log has to be shown
-        if appliLog == application:
-            return True, appliLog
-        elif application != 'None':
-            return False, appliLog
-        
-        return True, appliLog
+    root_node.attrib.update(attrib)
+
+def find_node_by_attrib(xmlroot, name_node, key, value):
+    '''Find the nfirst ode from xmlroot that has name name_node and that has in 
+       its attributes {key : value}. Return the node
     
-    if application == 'None':
-            return True, None    
-        
-    return False, None
+    :param xmlroot etree.Element: the Etree element where to search
+    :param name_node str: the name of node to search
+    :param key str: the key to search
+    :param value str: the value to search
+    :return: the found node
+    :rtype: xmlroot etree.Element
+    '''
+    l_nodes =  xmlroot.findall(name_node)
+    for node in l_nodes:
+        if key not in node.attrib.keys():
+            continue
+        if node.attrib[key] == value:
+            return node
+    return None
     
 
-def update_hat_xml(logDir, application=None, notShownCommands = []):
-    '''Create the xml file in logDir that contain all the xml file and have a name like YYYYMMDD_HHMMSS_namecmd.xml
+def write_report(filename, xmlroot, stylesheet):
+    """Writes a report file from a XML tree.
     
-    :param logDir str: the directory to parse
-    :param application str: the name of the application if there is any
-    '''
-    # Create an instance of xmlLogFile class to create hat.xml file
-    xmlHatFilePath = os.path.join(logDir, 'hat.xml')
-    xmlHat = xmlLogFile(xmlHatFilePath,  "LOGlist", {"application" : application})
-    # parse the log directory to find all the command logs, then add it to the xml file
-    for fileName in os.listdir(logDir):
-        # YYYYMMDD_HHMMSS_namecmd.xml
-        sExpr = "^[0-9]{8}_+[0-9]{6}_+.*\.xml$"
-        oExpr = re.compile(sExpr)
-        if oExpr.search(fileName):
-            # get date and hour and format it
-            date_hour_cmd = fileName.split('_')
-            date_not_formated = date_hour_cmd[0]
-            date = "%s/%s/%s" % (date_not_formated[6:8], date_not_formated[4:6], date_not_formated[0:4] )
-            hour_not_formated = date_hour_cmd[1]
-            hour = "%s:%s:%s" % (hour_not_formated[0:2], hour_not_formated[2:4], hour_not_formated[4:6])
-            cmd = date_hour_cmd[2][:-len('.xml')]
-            showLog, cmdAppli = showcommandLog(os.path.join(logDir, fileName), cmd, application, notShownCommands)
-            #if cmd not in notShownCommands:
-            if showLog:
-                # add a node to the hat.xml file
-                xmlHat.add_simple_node("LogCommand", text=fileName, attrib = {"date" : date, "hour" : hour, "cmd" : cmd, "application" : cmdAppli})
+    :param filename str: The path to the file to create
+    :param xmlroot etree.Element: the Etree element to write to the file
+    :param stylesheet str: The stylesheet to add to the begin of the file
+    """
+    dirname = os.path.dirname(filename)
+    if not os.path.exists(dirname):
+      os.makedirs(dirname)
+    if len(stylesheet) > 0:
+       styleName = stylesheet
+    else:
+       styleName = None
+
+    with open(filename, "w") as f:
+      f.write("<?xml version='1.0' encoding='utf-8'?>\n")
+      if styleName is not None:
+        f.write("<?xml-stylesheet type='text/xsl' href='%s'?>\n" % styleName)
+      res = etree.tostring(xmlroot, encoding='utf-8')
+      # print("********** etree.tostring %s" % res)
+      f.write(res)
+
+    # create fileStyle in dirname if not existing
+    if styleName is not None:
+      styleFile = os.path.join(dirname, styleName)
+      if not os.path.exists(styleFile):
+        # copy if from "salomeTools/src/xsl"
+        srcdir = os.path.dirname(src.__file__)
+        srcFile = os.path.join(srcdir, "xsl", styleName)
+        if verbose: print("write_report %s style %s" % (srcFile, styleFile))
+        shutil.copy(srcFile, dirname)
+
+def escapeSequence(aStr):
+    """
+    See xml specification:
+    The ampersand character(&) and the left angle bracket(<) MUST NOT appear in their
+    literal form, except when used as markup delimiters, or within a comment, a processing
+    instruction, or a CDATA section.
+    If they are needed elsewhere, they MUST be escaped using either numeric character references
+    or the strings '&amp;' and '&lt;' respectively.
+    The right angle bracket(>) may be
+    represented using the string '&gt;', and MUST,
+    for compatibility, be escaped using either '&gt;' or a character reference
+    when it appears in the string " ]]> " in content,
+    when that string is not marking the end of a CDATA section.
+    You can use these escape sequences:
+    < (less - than) as &#60; or &lt;
+    > (greater - than) as &#62; or &gt;
+    & (ampersand) as &#38;
+    ' (apostrophe or single quote) as &#39;
+    " (double-quote) as &#34;
+    """
+    replaces = [ ('&', '&amp;'),
+                 ('>', '&gt;'),
+                 ('<', '&lt;'),
+                 ("'", '&#39;'),
+                 ('"', '&#34;'),
+                ]
+    res = aStr
+    for ini, fin in replaces: # order matters
+      res = res.replace(ini, fin)
+    return res
+
     
-    # Write the file on the hard drive
-    xmlHat.write_tree('hat.xsl')
\ No newline at end of file