Replaced old list of pou instance in project generating process by xslt stylesheet
authorLaurent Bessard
Wed, 18 Sep 2013 15:30:46 +0200
changeset 1319 748347102c97
parent 1318 758801f4b296
child 1320 bb04c41cbee9
Replaced old list of pou instance in project generating process by xslt stylesheet
PLCControler.py
plcopen/instances_path.xslt
plcopen/pou_variables.xslt
--- a/PLCControler.py	Wed Sep 18 15:26:33 2013 +0200
+++ b/PLCControler.py	Wed Sep 18 15:30:46 2013 +0200
@@ -140,18 +140,19 @@
 
 class VarTree(etree.XSLTExtension):
     
-    def __init__(self, controller):
+    def __init__(self, controller, debug):
         etree.XSLTExtension.__init__(self)
         self.Controller = controller
+        self.Debug = debug
     
     def execute(self, context, self_node, input_node, output_parent):
         typename = input_node.get("name")
-        pou_infos = self.Controller.GetPou(typename)
+        pou_infos = self.Controller.GetPou(typename, self.Debug)
         if pou_infos is not None:
             self.apply_templates(context, pou_infos, output_parent)
             return
         
-        datatype_infos = self.Controller.GetDataType(typename)
+        datatype_infos = self.Controller.GetDataType(typename, self.Debug)
         if datatype_infos is not None:
             self.apply_templates(context, datatype_infos, output_parent)
             return
@@ -164,9 +165,10 @@
 #-------------------------------------------------------------------------------
 
 def class_extraction(el, prt):
-    if prt == "pou":
-        return POU_TYPES[el.text]
-    elif prt == "variable":
+    if prt in ["pou", "variable"]:
+        pou_type = POU_TYPES.get(el.text)
+        if pou_type is not None:
+            return pou_type
         return VAR_CLASS_INFOS[el.text][1]
     return {
         "configuration": ITEM_CONFIGURATION,
@@ -200,10 +202,8 @@
     def execute(self, context, self_node, input_node, output_parent):
         typename = input_node.get("name")
         project = self.Controller.GetProject(self.Debug)
-        infos = etree.Element('{http://www.w3.org/1999/XSL/Transform}text')
-        infos.text = str(project.getpou(typename) is not None)
-        self.process_children(context, infos)
-
+        output_parent.text = str(project.getpou(typename) is not None)
+        
 class IsDebugged(etree.XSLTExtension):
     
     def __init__(self, controller, debug):
@@ -223,11 +223,62 @@
         if datatype_infos is not None:
             self.apply_templates(context, datatype_infos, output_parent)
             return
-
+        
+        output_parent.text = "False"
+        
+class PouVariableClass(etree.XSLTExtension):
+    
+    def __init__(self, controller, debug):
+        etree.XSLTExtension.__init__(self)
+        self.Controller = controller
+        self.Debug = debug
+    
+    def execute(self, context, self_node, input_node, output_parent):
+        pou_infos = self.Controller.GetPou(input_node.get("name"), self.Debug)
+        if pou_infos is not None:
+            self.apply_templates(context, pou_infos, output_parent)
+            return
+        
+        self.process_children(context, output_parent)
+        
 pou_variables_xslt = etree.parse(
     os.path.join(ScriptDirectory, "plcopen", "pou_variables.xslt"))
 
 #-------------------------------------------------------------------------------
+#            Helpers object for generating instances path list
+#-------------------------------------------------------------------------------
+
+class InstanceDefinition(etree.XSLTExtension):
+    
+    def __init__(self, controller, debug):
+        etree.XSLTExtension.__init__(self)
+        self.Controller = controller
+        self.Debug = debug
+    
+    def execute(self, context, self_node, input_node, output_parent):
+        instance_infos = etree.Element('infos')
+        self.process_children(context, instance_infos)
+        
+        pou_infos = self.Controller.GetPou(instance_infos.get("name"), self.Debug)
+        if pou_infos is not None:
+            pou_instance = etree.Element('pou_instance',
+                pou_path=instance_infos.get("path"))
+            pou_instance.append(deepcopy(pou_infos))
+            self.apply_templates(context, pou_instance, output_parent)
+            return
+            
+        datatype_infos = self.Controller.GetDataType(instance_infos.get("name"), self.Debug)
+        if datatype_infos is not None:
+            datatype_instance = etree.Element('datatype_instance',
+                datatype_path=instance_infos.get("path"))
+            datatype_instance.append(deepcopy(datatype_infos))
+            self.apply_templates(context, datatype_instance, output_parent)
+            return
+
+instances_path_xslt = etree.parse(
+    os.path.join(ScriptDirectory, "plcopen", "instances_path.xslt"))
+
+#-------------------------------------------------------------------------------
 #                         Undo Buffer for PLCOpenEditor
 #-------------------------------------------------------------------------------
 
@@ -525,65 +576,41 @@
             pou_variable_xslt_tree = etree.XSLT(
                 pou_variables_xslt, extensions = {
                     ("pou_vars_ns", "is_edited"): IsEdited(self, debug),
-                    ("pou_vars_ns", "is_debugged"): IsDebugged(self, debug)})
-            return compute_instance_tree(
-                pou_variable_xslt_tree(
-                    self.GetEditedElement(tagname, debug)).getroot())
-
-    def RecursiveSearchPouInstances(self, project, pou_type, parent_path, varlists, debug = False):
-        instances = []
-        for varlist in varlists:
-            for variable in varlist.getvariable():
-                vartype_content = variable.gettype().getcontent()
-                if vartype_content.getLocalTag() == "derived":
-                    var_path = "%s.%s" % (parent_path, variable.getname())
-                    var_type = vartype_content.getname()
-                    if var_type == pou_type:
-                        instances.append(var_path)
-                    else:
-                        pou = project.getpou(var_type)
-                        if pou is not None:# and project.ElementIsUsedBy(pou_type, var_type):
-                            instances.extend(
-                                self.RecursiveSearchPouInstances(
-                                    project, pou_type, var_path, 
-                                    [varlist for type, varlist in pou.getvars()], 
-                                    debug))
-        return instances
-                        
-    def SearchPouInstances(self, tagname, debug = False):
-        project = self.GetProject(debug)
-        if project is not None:
+                    ("pou_vars_ns", "is_debugged"): IsDebugged(self, debug),
+                    ("pou_vars_ns", "pou_class"): PouVariableClass(self, debug)})
+            
             words = tagname.split("::")
             if words[0] == "P":
-                instances = []
-                for config in project.getconfigurations():
-                    config_name = config.getname()
-                    instances.extend(
-                        self.RecursiveSearchPouInstances(
-                            project, words[1], config_name, 
-                            config.getglobalVars(), debug))
-                    for resource in config.getresource():
-                        res_path = "%s.%s" % (config_name, resource.getname())
-                        instances.extend(
-                            self.RecursiveSearchPouInstances(
-                                project, words[1], res_path, 
-                                resource.getglobalVars(), debug))
-                        pou_instances = resource.getpouInstance()[:]
-                        for task in resource.gettask():
-                            pou_instances.extend(task.getpouInstance())
-                        for pou_instance in pou_instances:
-                            pou_path = "%s.%s" % (res_path, pou_instance.getname())
-                            pou_type = pou_instance.gettypeName()
-                            if pou_type == words[1]:
-                                instances.append(pou_path)
-                            pou = project.getpou(pou_type)
-                            if pou is not None:# and project.ElementIsUsedBy(words[1], pou_type):
-                                instances.extend(
-                                    self.RecursiveSearchPouInstances(
-                                        project, words[1], pou_path, 
-                                        [varlist for type, varlist in pou.getvars()], 
-                                        debug))
-                return instances
+                obj = self.GetPou(words[1], debug)
+            else:
+                obj = self.GetEditedElement(tagname, debug)
+            if obj is not None:
+                return compute_instance_tree(
+                        pou_variable_xslt_tree(obj).getroot())
+        return []
+
+    def GetInstanceList(self, root, name, debug = False):
+        project = self.GetProject(debug)
+        if project is not None:
+            instances_path_xslt_tree = etree.XSLT(
+                instances_path_xslt, 
+                extensions = {
+                    ("instances_ns", "instance_definition"): 
+                    InstanceDefinition(self, debug)})
+            
+            return instances_path_xslt_tree(root, 
+                instance_type=etree.XSLT.strparam(name)).getroot()
+        return None
+
+    def SearchPouInstances(self, tagname, debug = False):
+        project = self.GetProject(debug)
+        if project is not None:
+            words = tagname.split("::")
+            if words[0] == "P":
+                result = self.GetInstanceList(project, words[1])
+                if result is not None:
+                    return [instance.get("path") for instance in result]
+                return []
             elif words[0] == 'C':
                 return [words[1]]
             elif words[0] == 'R':
@@ -607,7 +634,7 @@
                         if vartype_content.getLocalTag() == "derived":
                             return self.RecursiveGetPouInstanceTagName(
                                             project, 
-                                            vartype_content["value"].getname(),
+                                            vartype_content.getname(),
                                             parts[1:], debug)
             
             if pou.getbodyType() == "SFC" and len(parts) == 1:
@@ -707,23 +734,23 @@
     
     # Return if data type given by name is used by another data type or pou
     def DataTypeIsUsed(self, name, debug = False):
-        #project = self.GetProject(debug)
-        #if project is not None:
-        #    return project.ElementIsUsed(name)
+        project = self.GetProject(debug)
+        if project is not None:
+            return self.GetInstanceList(project, name, debug) is not None
         return False
 
     # Return if pou given by name is used by another pou
     def PouIsUsed(self, name, debug = False):
-        #project = self.GetProject(debug)
-        #if project is not None:
-        #    return project.ElementIsUsed(name)
+        project = self.GetProject(debug)
+        if project is not None:
+            return self.GetInstanceList(project, name, debug) is not None
         return False
 
     # Return if pou given by name is directly or undirectly used by the reference pou
     def PouIsUsedBy(self, name, reference, debug = False):
-        #project = self.GetProject(debug)
-        #if project is not None:
-        #    return project.ElementIsUsedBy(name, reference)
+        pou_infos = self.GetPou(reference, debug)
+        if pou_infos is not None:
+            return self.GetInstanceList(pou_infos, name, debug) is not None
         return False
 
     def GenerateProgram(self, filepath=None):
@@ -1202,13 +1229,13 @@
             current_varlist.appendvariable(tempvar)
         return varlist_list
     
-    def GetVariableDictionary(self, object_with_vars):
+    def GetVariableDictionary(self, object_with_vars, debug=False):
         variables = []
         
         variables_infos_xslt_tree = etree.XSLT(
             variables_infos_xslt, extensions = {
                 ("var_infos_ns", "add_variable"): AddVariable(variables),
-                ("var_infos_ns", "var_tree"): VarTree(self)})
+                ("var_infos_ns", "var_tree"): VarTree(self, debug)})
         variables_infos_xslt_tree(object_with_vars)
         
         return variables
@@ -1244,7 +1271,7 @@
             configuration = project.getconfiguration(name)
             if configuration is not None:
                 # Extract variables defined in configuration
-                return self.GetVariableDictionary(configuration)
+                return self.GetVariableDictionary(configuration, debug)
         
         return []
 
@@ -1281,7 +1308,7 @@
             resource = project.getconfigurationResource(config_name, name)
             if resource is not None:
                 # Extract variables defined in configuration
-                return self.GetVariableDictionary(resource)
+                return self.GetVariableDictionary(resource, debug)
         
         return []
     
@@ -1308,7 +1335,7 @@
         # Verify that the pou has an interface
         if interface is not None:
             # Extract variables defined in interface
-            return self.GetVariableDictionary(interface)
+            return self.GetVariableDictionary(interface, debug)
         return []
 
     # Replace the Pou interface by the one given
@@ -1492,24 +1519,29 @@
                 for category in self.TotalTypes]
             blocktypes.append({"name" : USER_DEFINED_POUS, 
                 "list": [pou.getblockInfos()
-                         for pou in project.getpous(name, filter)]})
+                         for pou in project.getpous(name, filter)
+                         if (name is None or 
+                             self.GetInstanceList(pou, name, debug) is None)]})
             return blocktypes
         return self.TotalTypes
 
     # Return Function Block types checking for recursion
     def GetFunctionBlockTypes(self, tagname = "", debug = False):
+        project = self.GetProject(debug)
+        words = tagname.split("::")
+        name = None
+        if project is not None and words[0] in ["P","T","A"]:
+            name = words[1]
         blocktypes = []
         for blocks in self.TotalTypesDict.itervalues():
             for sectioname,block in blocks:
                 if block["type"] == "functionBlock":
                     blocktypes.append(block["name"])
-        project = self.GetProject(debug)
-        if project is not None:
-            words = tagname.split("::")
+        if project is not None:
             blocktypes.extend([pou.getname()
-                for pou in project.getpous(
-                    words[1] if words[0] in ["P","T","A"] else None,
-                    ["functionBlock"])])
+                for pou in project.getpous(name, ["functionBlock"])
+                if (name is None or 
+                    self.GetInstanceList(pou, name, debug) is None)])
         return blocktypes
 
     # Return Block types checking for recursion
@@ -1541,7 +1573,9 @@
             datatypes.extend([
                 datatype.getname() 
                 for datatype in project.getdataTypes(name)
-                if not only_locatables or self.IsLocatableDataType(datatype, debug)])
+                if (not only_locatables or self.IsLocatableDataType(datatype, debug))
+                    and (name is None or 
+                         self.GetInstanceList(datatype, name, debug) is None)])
         if confnodetypes:
             for category in self.GetConfNodeDataTypes(name, only_locatables):
                 datatypes.extend(category["list"])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plcopen/instances_path.xslt	Wed Sep 18 15:30:46 2013 +0200
@@ -0,0 +1,137 @@
+<xsl:stylesheet version="1.0"
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns:ppx="http://www.plcopen.org/xml/tc6_0201"
+    xmlns:ns="instances_ns"
+    extension-element-prefixes="ns"
+    exclude-result-prefixes="ns">
+  <xsl:param name="instance_type"/>
+  <xsl:template match="ppx:project">
+   <instances>
+     <xsl:apply-templates select="ppx:instances/ppx:configurations/ppx:configuration"/>
+   </instances>
+  </xsl:template>
+  <xsl:template match="ppx:configuration">
+    <xsl:apply-templates select="ppx:globalVars/ppx:variable[ppx:type/ppx:derived]">
+      <xsl:with-param name="parent_path" select="@name"/>
+    </xsl:apply-templates>
+    <xsl:apply-templates select="ppx:resource">
+      <xsl:with-param name="parent_path" select="@name"/>
+    </xsl:apply-templates>
+  </xsl:template>
+  <xsl:template match="ppx:resource">
+    <xsl:param name="parent_path"/>
+    <xsl:variable name="resource_path">
+      <xsl:value-of select="$parent_path"/>
+      <xsl:text>.</xsl:text>
+      <xsl:value-of select="@name"/>
+    </xsl:variable>
+    <xsl:apply-templates select="ppx:globalVars/ppx:variable[ppx:type/ppx:derived]">
+      <xsl:with-param name="parent_path" select="$resource_path"/>
+    </xsl:apply-templates>
+    <xsl:apply-templates select="ppx:pouInstance | ppx:task/ppx:pouInstance">
+      <xsl:with-param name="parent_path" select="$resource_path"/>
+    </xsl:apply-templates>
+  </xsl:template>
+  <xsl:template match="ppx:pouInstance">
+    <xsl:param name="parent_path"/>
+    <xsl:variable name="pou_instance_path">
+      <xsl:value-of select="$parent_path"/>
+      <xsl:text>.</xsl:text>
+      <xsl:value-of select="@name"/>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="@typeName=$instance_type">
+        <instance>
+          <xsl:attribute name="path">
+            <xsl:value-of select="$pou_instance_path"/>
+          </xsl:attribute>
+        </instance>
+      </xsl:when>
+      <xsl:otherwise>
+        <ns:instance_definition>
+          <xsl:attribute name="name">
+            <xsl:value-of select="@typeName"/>
+          </xsl:attribute>
+          <xsl:attribute name="path">
+            <xsl:value-of select="$pou_instance_path"/>
+          </xsl:attribute>
+        </ns:instance_definition>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+  <xsl:template match="ppx:pou">
+    <xsl:param name="instance_path"/>
+    <xsl:apply-templates select="ppx:interface/*/ppx:variable[ppx:type/ppx:derived]">
+      <xsl:with-param name="parent_path" select="$instance_path"/>
+    </xsl:apply-templates>
+  </xsl:template>
+  <xsl:template match="ppx:dataType">
+    <xsl:param name="instance_path"/>
+    <xsl:apply-templates select="ppx:baseType/*[self::ppx:derived or self::ppx:struct or self::ppx:array]">
+      <xsl:with-param name="parent_path" select="$instance_path"/>
+    </xsl:apply-templates>
+  </xsl:template>
+  <xsl:template match="ppx:variable">
+    <xsl:param name="parent_path"/>
+    <xsl:variable name="variable_path">
+      <xsl:value-of select="$parent_path"/>
+      <xsl:text>.</xsl:text>
+      <xsl:value-of select="@name"/>
+    </xsl:variable>
+    <xsl:apply-templates select="ppx:type/ppx:derived">
+      <xsl:with-param name="variable_path" select="$variable_path"/>
+    </xsl:apply-templates>
+  </xsl:template>
+  <xsl:template match="ppx:derived">
+    <xsl:param name="variable_path"/>
+    <xsl:choose>
+      <xsl:when test="@name=$instance_type">
+        <instance>
+          <xsl:attribute name="path">
+            <xsl:value-of select="$variable_path"/>
+          </xsl:attribute>
+        </instance>
+      </xsl:when>
+      <xsl:otherwise>
+        <ns:instance_definition>
+          <xsl:attribute name="name">
+            <xsl:value-of select="@name"/>
+          </xsl:attribute>
+          <xsl:attribute name="path">
+            <xsl:value-of select="$variable_path"/>
+          </xsl:attribute>
+        </ns:instance_definition>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+  <xsl:template name="ppx:struct">
+    <xsl:param name="variable_path"/>
+    <xsl:for-each select="ppx:variable[ppx:type/ppx:derived or ppx:type/ppx:struct or ppx:type/ppx:array]">
+      <xsl:variable name="element_path">
+        <xsl:value-of select="$variable_path"/>
+        <xsl:text>.</xsl:text>
+        <xsl:value-of select="@name"/>
+      </xsl:variable>
+      <xsl:apply-templates select="ppx:type/*[self::ppx:derived or self::ppx:struct or self::ppx:array]">
+        <xsl:with-param name="variable_path" select="$element_path"/>
+      </xsl:apply-templates>
+    </xsl:for-each>
+  </xsl:template>
+  <xsl:template name="ppx:array">
+    <xsl:param name="variable_path"/>
+    <xsl:apply-templates select="ppx:baseType/*[self::ppx:derived or self::ppx:struct or self::ppx:array]">
+      <xsl:with-param name="variable_path" select="$variable_path"/>
+    </xsl:apply-templates> 
+  </xsl:template>
+  <xsl:template match="pou_instance">
+    <xsl:apply-templates>
+      <xsl:with-param name="instance_path" select="@pou_path"/>
+    </xsl:apply-templates>
+  </xsl:template>
+  <xsl:template match="datatype_instance">
+    <xsl:apply-templates>
+      <xsl:with-param name="instance_path" select="@datatype_path"/>
+    </xsl:apply-templates>
+  </xsl:template>
+  <xsl:template match="text()"/>
+</xsl:stylesheet>
\ No newline at end of file
--- a/plcopen/pou_variables.xslt	Wed Sep 18 15:26:33 2013 +0200
+++ b/plcopen/pou_variables.xslt	Wed Sep 18 15:30:46 2013 +0200
@@ -102,7 +102,13 @@
 	<xsl:for-each select="ppx:variable">
       <variable>
 	    <name><xsl:value-of select="@name"/></name>
-	    <class><xsl:value-of select="$var_class"/></class>
+	    <class>
+	      <xsl:apply-templates mode="var_class">
+	        <xsl:with-param name="default_class">
+	          <xsl:value-of select="$var_class"/>
+	        </xsl:with-param>
+	      </xsl:apply-templates>
+	    </class>
 	    <type><xsl:apply-templates mode="var_type"/></type>
 	    <edit><xsl:apply-templates mode="var_edit"/></edit>
 	    <debug><xsl:apply-templates mode="var_debug"/></debug>
@@ -145,6 +151,20 @@
       <debug><xsl:text>True</xsl:text></debug>
     </program>
   </xsl:template>
+  <xsl:template match="*[self::ppx:type or self::ppx:baseType]/ppx:derived" mode="var_class">
+    <xsl:param name="default_class"/>
+    <ns:pou_class>
+      <xsl:value-of select="$default_class"/>
+    </ns:pou_class>
+  </xsl:template>
+  <xsl:template match="ppx:pou" mode="var_class">
+    <xsl:param name="default_class"/>
+    <xsl:value-of select="@pouType"/>
+  </xsl:template>
+  <xsl:template match="*[self::ppx:type or self::ppx:baseType]/*" mode="var_class">
+    <xsl:param name="default_class"/>
+    <xsl:value-of select="$default_class"/>
+  </xsl:template>
   <xsl:template match="*[self::ppx:type or self::ppx:baseType]/ppx:derived" mode="var_type">
     <xsl:value-of select="@name"/>
   </xsl:template>
@@ -178,14 +198,6 @@
   </xsl:template>
     <xsl:template match="*[self::ppx:type or self::ppx:baseType]/ppx:derived" mode="var_debug">
     <ns:is_debugged/>
-    <xsl:choose>
-      <xsl:when test="count(./*) > 0">
-        <xsl:apply-templates mode="var_debug"/>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:text>False</xsl:text>
-      </xsl:otherwise>
-    </xsl:choose>
   </xsl:template>
   <xsl:template match="ppx:pou" mode="var_debug">
     <xsl:text>True</xsl:text>
@@ -200,6 +212,7 @@
     <xsl:text>True</xsl:text>
   </xsl:template>
   <xsl:template match="text()"/>
+  <xsl:template match="text()" mode="var_class"/>
   <xsl:template match="text()" mode="var_type"/>
   <xsl:template match="text()" mode="var_edit"/>
   <xsl:template match="text()" mode="var_debug"/>