beremiz

Parents 26e8b99bc2c3
Children 85ce56758900
Replaced old pou variable list and variable tree generating by xslt stylesheet
--- a/PLCControler.py Mon Sep 09 00:48:34 2013 +0200
+++ b/PLCControler.py Mon Sep 09 23:36:12 2013 +0200
@@ -24,6 +24,7 @@
from xml.dom import minidom
from types import StringType, UnicodeType, TupleType
+from lxml import etree
from copy import deepcopy
import os,sys,re
import datetime
@@ -99,6 +100,66 @@
RESOURCES, PROPERTIES] = UNEDITABLE_NAMES
#-------------------------------------------------------------------------------
+# Helpers object for generating pou var list
+#-------------------------------------------------------------------------------
+
+def compute_dimensions(el):
+ return [
+ (dimension.get("lower"), dimension.get("upper"))
+ for dimension in el.findall("dimension")]
+
+def extract_param(el):
+ if el.tag == "Type" and el.text is None:
+ array = el.find("array")
+ return ('array', array.text, compute_dimensions(array))
+ elif el.tag == "Tree":
+ return generate_var_tree(el)
+ elif el.tag == "Edit":
+ return True
+ elif el.text is None:
+ return ''
+ return el.text
+
+def generate_var_tree(tree):
+ return ([
+ (var.get("name"), var.text, generate_var_tree(var))
+ for var in tree.findall("var")],
+ compute_dimensions(tree))
+
+class AddVariable(etree.XSLTExtension):
+
+ def __init__(self, variables):
+ etree.XSLTExtension.__init__(self)
+ self.Variables = variables
+
+ def execute(self, context, self_node, input_node, output_parent):
+ infos = etree.Element('var_infos')
+ self.process_children(context, infos)
+ self.Variables.append(
+ {el.tag.replace("_", " "): extract_param(el) for el in infos})
+
+class VarTree(etree.XSLTExtension):
+
+ def __init__(self, controller):
+ etree.XSLTExtension.__init__(self)
+ self.Controller = controller
+
+ def execute(self, context, self_node, input_node, output_parent):
+ typename = input_node.get("name")
+ pou_infos = self.Controller.GetPou(typename)
+ if pou_infos is not None:
+ self.apply_templates(context, pou_infos, output_parent)
+ return
+
+ datatype_infos = self.Controller.GetDataType(typename)
+ if datatype_infos is not None:
+ self.apply_templates(context, datatype_infos, output_parent)
+ return
+
+variables_infos_xslt = etree.parse(
+ os.path.join(ScriptDirectory, "plcopen", "variables_infos.xslt"))
+
+#-------------------------------------------------------------------------------
# Undo Buffer for PLCOpenEditor
#-------------------------------------------------------------------------------
@@ -1224,63 +1285,17 @@
current_varlist.appendvariable(tempvar)
return varlist_list
- def GetVariableDictionary(self, varlist, var):
- '''
- convert a PLC variable to the dictionary representation
- returned by Get*Vars)
- '''
-
- tempvar = {"Name": var.getname()}
-
- vartype_content = var.gettype().getcontent()
- vartype_content_type = vartype_content.getLocalTag()
- if vartype_content_type == "derived":
- tempvar["Type"] = vartype_content.getname()
- elif vartype_content_type == "array":
- dimensions = []
- for dimension in vartype_content.getdimension():
- dimensions.append((dimension.getlower(), dimension.getupper()))
- base_type = vartype_content.baseType.getcontent()
- base_type_type = base_type.getLocalTag()
- if base_type_type == "derived":
- base_type_name = base_type.getname()
- else:
- base_type_name = base_type_type.upper()
- tempvar["Type"] = ("array", base_type_name, dimensions)
- else:
- tempvar["Type"] = vartype_content_type.upper()
-
- tempvar["Edit"] = True
+ def GetVariableDictionary(self, object_with_vars):
+ variables = []
- initial = var.getinitialValue()
- if initial is not None:
- tempvar["Initial Value"] = initial.getvalue()
- else:
- tempvar["Initial Value"] = ""
-
- address = var.getaddress()
- if address:
- tempvar["Location"] = address
- else:
- tempvar["Location"] = ""
-
- if varlist.getconstant():
- tempvar["Option"] = "Constant"
- elif varlist.getretain():
- tempvar["Option"] = "Retain"
- elif varlist.getnonretain():
- tempvar["Option"] = "Non-Retain"
- else:
- tempvar["Option"] = ""
-
- doc = var.getdocumentation()
- if doc is not None:
- tempvar["Documentation"] = doc.getanyText()
- else:
- tempvar["Documentation"] = ""
-
- return tempvar
-
+ variables_infos_xslt_tree = etree.XSLT(
+ variables_infos_xslt, extensions = {
+ ("var_infos_ns", "add_variable"): AddVariable(variables),
+ ("var_infos_ns", "var_tree"): VarTree(self)})
+ variables_infos_xslt_tree(object_with_vars)
+
+ return variables
+
# Add a global var to configuration to configuration
def AddConfigurationGlobalVar(self, config_name, type, var_name,
location="", description=""):
@@ -1304,19 +1319,15 @@
# Return the configuration globalvars
def GetConfigurationGlobalVars(self, name, debug = False):
- vars = []
project = self.GetProject(debug)
if project is not None:
# Found the configuration corresponding to name
configuration = project.getconfiguration(name)
if configuration is not None:
- # Extract variables from every varLists
- for varlist in configuration.getglobalVars():
- for var in varlist.getvariable():
- tempvar = self.GetVariableDictionary(varlist, var)
- tempvar["Class"] = "Global"
- vars.append(tempvar)
- return vars
+ # Extract variables defined in configuration
+ return self.GetVariableDictionary(configuration)
+
+ return []
# Return configuration variable names
def GetConfigurationVariableNames(self, config_name = None, debug = False):
@@ -1345,19 +1356,15 @@
# Return the resource globalvars
def GetConfigurationResourceGlobalVars(self, config_name, name, debug = False):
- vars = []
project = self.GetProject(debug)
if project is not None:
# Found the resource corresponding to name
resource = project.getconfigurationResource(config_name, name)
if resource is not None:
- # Extract variables from every varLists
- for varlist in resource.getglobalVars():
- for var in varlist.getvariable():
- tempvar = self.GetVariableDictionary(varlist, var)
- tempvar["Class"] = "Global"
- vars.append(tempvar)
- return vars
+ # Extract variables defined in configuration
+ return self.GetVariableDictionary(resource)
+
+ return []
# Return resource variable names
def GetConfigurationResourceVariableNames(self,
@@ -1375,73 +1382,15 @@
for varlist in resource.globalVars],
[])])
return variables
-
- # Recursively generate element name tree for a structured variable
- def GenerateVarTree(self, typename, debug = False):
- project = self.GetProject(debug)
- if project is not None:
- blocktype = self.GetBlockType(typename, debug = debug)
- if blocktype is not None:
- tree = []
- en = False
- eno = False
- for var_name, var_type, var_modifier in blocktype["inputs"] + blocktype["outputs"]:
- en |= var_name.upper() == "EN"
- eno |= var_name.upper() == "ENO"
- tree.append((var_name, var_type, self.GenerateVarTree(var_type, debug)))
- if not eno:
- tree.insert(0, ("ENO", "BOOL", ([], [])))
- if not en:
- tree.insert(0, ("EN", "BOOL", ([], [])))
- return tree, []
- datatype = self.GetDataType(typename)
- if datatype is not None:
- tree = []
- basetype_content = datatype.baseType.getcontent()
- basetype_content_type = basetype_content.getLocalTag()
- if basetype_content_type == "derived":
- return self.GenerateVarTree(basetype_content.getname())
- elif basetype_content_type == "array":
- dimensions = []
- base_type = basetype_content.baseType.getcontent()
- if base_type.getLocalTag() == "derived":
- tree = self.GenerateVarTree(base_type.getname())
- if len(tree[1]) == 0:
- tree = tree[0]
- for dimension in basetype_content.getdimension():
- dimensions.append((dimension.getlower(), dimension.getupper()))
- return tree, dimensions
- elif basetype_content_type == "struct":
- for element in basetype_content.getvariable():
- element_type = element.type.getcontent()
- element_type_type = element_type.getLocalTag()
- if element_type_type == "derived":
- tree.append((element.getname(), element_type.getname(), self.GenerateVarTree(element_type.getname())))
- else:
- tree.append((element.getname(), element_type_type, ([], [])))
- return tree, []
- return [], []
# Return the interface for the given pou
def GetPouInterfaceVars(self, pou, debug = False):
- vars = []
+ interface = pou.interface
# Verify that the pou has an interface
- if pou.interface is not None:
- # Extract variables from every varLists
- for type, varlist in pou.getvars():
- for var in varlist.getvariable():
- tempvar = self.GetVariableDictionary(varlist, var)
-
- tempvar["Class"] = type
- tempvar["Tree"] = ([], [])
-
- vartype_content = var.gettype().getcontent()
- if vartype_content.getLocalTag() == "derived":
- tempvar["Edit"] = not pou.hasblock(tempvar["Name"])
- tempvar["Tree"] = self.GenerateVarTree(tempvar["Type"], debug)
-
- vars.append(tempvar)
- return vars
+ if interface is not None:
+ # Extract variables defined in interface
+ return self.GetVariableDictionary(interface)
+ return []
# Replace the Pou interface by the one given
def SetPouInterfaceVars(self, name, vars):
@@ -1503,13 +1452,13 @@
# Return the return type if there is one
return_type = pou.interface.getreturnType()
if return_type is not None:
- returntype_content = return_type.getcontent()
- returntype_content_type = returntype_content.getLocalTag()
- if returntype_content_type == "derived":
- return returntype_content.getname()
- else:
- return returntype_content_type.upper()
- return None
+ return_type_infos_xslt_tree = etree.XSLT(
+ variables_infos_xslt, extensions = {
+ ("var_infos_ns", "var_tree"): VarTree(self)})
+ return [extract_param(el)
+ for el in return_type_infos_xslt_tree(return_type).getroot()]
+
+ return [None, ([], [])]
# Function that add a new confnode to the confnode list
def AddConfNodeTypesList(self, typeslist):
@@ -1680,6 +1629,20 @@
return datatypes
# Return Data Type Object
+ def GetPou(self, typename, debug = False):
+ project = self.GetProject(debug)
+ if project is not None:
+ result = project.getpou(typename)
+ if result is not None:
+ return result
+ for confnodetype in self.ConfNodeTypes:
+ result = confnodetype["types"].getpou(typename)
+ if result is not None:
+ return result
+ return None
+
+
+ # Return Data Type Object
def GetDataType(self, typename, debug = False):
project = self.GetProject(debug)
if project is not None:
--- a/controls/VariablePanel.py Mon Sep 09 00:48:34 2013 +0200
+++ b/controls/VariablePanel.py Mon Sep 09 23:36:12 2013 +0200
@@ -173,7 +173,7 @@
if var_class not in ["External", "InOut"]:
if self.Parent.Controler.IsEnumeratedType(var_type):
editor = wx.grid.GridCellChoiceEditor()
- editor.SetParameters(",".join(self.Parent.Controler.GetEnumeratedDataValues(var_type)))
+ editor.SetParameters(",".join([""] + self.Parent.Controler.GetEnumeratedDataValues(var_type)))
else:
editor = wx.grid.GridCellTextEditor()
renderer = wx.grid.GridCellStringRenderer()
@@ -635,7 +635,7 @@
self.ReturnType.Clear()
for data_type in self.Controler.GetDataTypes(self.TagName, debug=self.Debug):
self.ReturnType.Append(data_type)
- returnType = self.Controler.GetEditedElementInterfaceReturnType(self.TagName)
+ returnType, (var_tree, dimensions) = self.Controler.GetEditedElementInterfaceReturnType(self.TagName)
description = self.Controler.GetPouDescription(words[1])
self.Values = self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)
--- a/editors/TextViewer.py Mon Sep 09 00:48:34 2013 +0200
+++ b/editors/TextViewer.py Mon Sep 09 23:36:12 2013 +0200
@@ -460,9 +460,8 @@
words = self.TagName.split("::")
self.Variables = self.GenerateVariableTree([(variable["Name"], variable["Type"], variable["Tree"]) for variable in self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)])
if self.Controler.GetEditedElementType(self.TagName, self.Debug)[1] == "function" or words[0] == "T" and self.TextSyntax == "IL":
- return_type = self.Controler.GetEditedElementInterfaceReturnType(self.TagName, self.Debug)
+ return_type, (var_tree, var_dimension) = self.Controler.GetEditedElementInterfaceReturnType(self.TagName, self.Debug)
if return_type is not None:
- var_tree, var_dimension = self.Controler.GenerateVarTree(return_type, self.Debug)
self.Variables[words[-1].upper()] = self.GenerateVariableTree(var_tree)
else:
self.Variables[words[-1].upper()] = {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/plcopen/variables_infos.xslt Mon Sep 09 23:36:12 2013 +0200
@@ -0,0 +1,207 @@
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:ppx="http://www.plcopen.org/xml/tc6_0201"
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
+ xmlns:ns="var_infos_ns"
+ extension-element-prefixes="ns"
+ exclude-result-prefixes="ns">
+ <xsl:template match="ppx:returnType">
+ <ReturnType>
+ <Type><xsl:apply-templates/></Type>
+ <Tree><xsl:apply-templates mode="var_tree"/></Tree>
+ </ReturnType>
+ </xsl:template>
+ <xsl:template match="ppx:localVars">
+ <xsl:call-template name="variables_infos">
+ <xsl:with-param name="var_class" select="'Local'"/>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template match="ppx:globalVars">
+ <xsl:call-template name="variables_infos">
+ <xsl:with-param name="var_class" select="'Global'"/>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template match="ppx:externalVars">
+ <xsl:call-template name="variables_infos">
+ <xsl:with-param name="var_class" select="'External'"/>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template match="ppx:tempVars">
+ <xsl:call-template name="variables_infos">
+ <xsl:with-param name="var_class" select="'Temp'"/>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template match="ppx:inputVars">
+ <xsl:call-template name="variables_infos">
+ <xsl:with-param name="var_class" select="'Input'"/>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template match="ppx:outputVars">
+ <xsl:call-template name="variables_infos">
+ <xsl:with-param name="var_class" select="'Output'"/>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template match="inOutVars">
+ <xsl:call-template name="variables_infos">
+ <xsl:with-param name="var_class" select="'InOut'"/>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template name="variables_infos">
+ <xsl:param name="var_class"/>
+ <xsl:variable name="var_option">
+ <xsl:choose>
+ <xsl:when test="@constant='true' or @constant='1'">
+ <xsl:text>Constant</xsl:text>
+ </xsl:when>
+ <xsl:when test="@retain='true' or @retain='1'">
+ <xsl:text>Retain</xsl:text>
+ </xsl:when>
+ <xsl:when test="@nonretain='true' or @nonretain='1'">
+ <xsl:text>Non-Retain</xsl:text>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:for-each select="ppx:variable">
+ <ns:add_variable>
+ <Name><xsl:value-of select="@name"/></Name>
+ <Class><xsl:value-of select="$var_class"/></Class>
+ <Type><xsl:apply-templates select="ppx:type"/></Type>
+ <Option><xsl:value-of select="$var_option"/></Option>
+ <Location><xsl:value-of select="@address"/></Location>
+ <Initial_Value><xsl:apply-templates select="ppx:initialValue"/></Initial_Value>
+ <Edit/>
+ <Tree><xsl:apply-templates select="ppx:type" mode="var_tree"/></Tree>
+ <Documentation>
+ <xsl:value-of select="ppx:documentation/xhtml:p/text()"/>
+ </Documentation>
+ </ns:add_variable>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:derived">
+ <xsl:value-of select="@name"/>
+ </xsl:template>
+ <xsl:template match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:array">
+ <array>
+ <xsl:apply-templates select="ppx:baseType"/>
+ <xsl:for-each select="ppx:dimension">
+ <dimension>
+ <xsl:attribute name="lower">
+ <xsl:value-of select="@lower"/>
+ </xsl:attribute>
+ <xsl:attribute name="upper">
+ <xsl:value-of select="@upper"/>
+ </xsl:attribute>
+ </dimension>
+ </xsl:for-each>
+ </array>
+ </xsl:template>
+ <xsl:template match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:string">
+ <xsl:text>STRING</xsl:text>
+ </xsl:template>
+ <xsl:template match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:wstring">
+ <xsl:text>WSTRING</xsl:text>
+ </xsl:template>
+ <xsl:template match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/*">
+ <xsl:value-of select="local-name()"/>
+ </xsl:template>
+ <xsl:template match="ppx:initialValue">
+ <xsl:apply-templates/>
+ </xsl:template>
+ <xsl:template match="ppx:value">
+ <xsl:choose>
+ <xsl:when test="@repetitionValue">
+ <xsl:value-of select="@repetitionValue"/>
+ <xsl:text>(</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>)</xsl:text>
+ </xsl:when>
+ <xsl:when test="@member">
+ <xsl:value-of select="@member"/>
+ <xsl:text> := </xsl:text>
+ <xsl:apply-templates/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template match="ppx:simpleValue">
+ <xsl:value-of select="@value"/>
+ </xsl:template>
+ <xsl:template match="ppx:arrayValue">
+ <xsl:text>[</xsl:text>
+ <xsl:for-each select="ppx:value">
+ <xsl:apply-templates select="."/>
+ <xsl:choose>
+ <xsl:when test="position()!=last()">
+ <xsl:text>, </xsl:text>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:for-each>
+ <xsl:text>]</xsl:text>
+ </xsl:template>
+ <xsl:template match="ppx:structValue">
+ <xsl:text>(</xsl:text>
+ <xsl:for-each select="ppx:value">
+ <xsl:apply-templates select="."/>
+ <xsl:choose>
+ <xsl:when test="position()!=last()">
+ <xsl:text>, </xsl:text>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:for-each>
+ <xsl:text>)</xsl:text>
+ </xsl:template>
+ <xsl:template match="ppx:pou" mode="var_tree">
+ <xsl:apply-templates select="ppx:interface/*[self::ppx:inputVars or self::ppx:inOutVars or self::ppx:outputVars]/ppx:variable" mode="var_tree"/>
+ </xsl:template>
+ <xsl:template match="ppx:variable" mode="var_tree">
+ <var>
+ <xsl:attribute name="name">
+ <xsl:value-of select="@name"/>
+ </xsl:attribute>
+ <xsl:apply-templates select="ppx:type" mode="var_tree"/>
+ </var>
+ </xsl:template>
+ <xsl:template match="ppx:dataType">
+ <xsl:apply-templates select="ppx:baseType" mode="var_tree"/>
+ </xsl:template>
+ <xsl:template match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:struct" mode="var_tree">
+ <xsl:apply-templates select="ppx:variable" mode="var_tree"/>
+ </xsl:template>
+ <xsl:template match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:derived" mode="var_tree">
+ <ns:var_tree/>
+ <xsl:choose>
+ <xsl:when test="count(./*) > 0">
+ <xsl:apply-templates mode="var_tree"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@name"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:array" mode="var_tree">
+ <xsl:apply-templates select="ppx:baseType" mode="var_tree"/>
+ <xsl:for-each select="ppx:dimension">
+ <dimension>
+ <xsl:attribute name="lower">
+ <xsl:value-of select="@lower"/>
+ </xsl:attribute>
+ <xsl:attribute name="upper">
+ <xsl:value-of select="@upper"/>
+ </xsl:attribute>
+ </dimension>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:string" mode="var_tree">
+ <xsl:text>STRING</xsl:text>
+ </xsl:template>
+ <xsl:template match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:wstring" mode="var_tree">
+ <xsl:text>WSTRING</xsl:text>
+ </xsl:template>
+ <xsl:template match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/*" mode="var_tree">
+ <xsl:value-of select="local-name()"/>
+ </xsl:template>
+ <xsl:template match="text()"/>
+ <xsl:template match="text()" mode="var_tree"/>
+</xsl:stylesheet>
\ No newline at end of file