GetPouVariables optimized with XSLTModelQuery
authorEdouard Tisserant <edouard.tisserant@gmail.com>
Sat, 17 Feb 2018 23:58:47 +0100
changeset 1943 9dc0e38552b2
parent 1942 a4382ae1ba82
child 1944 6162e34fb246
GetPouVariables optimized with XSLTModelQuery
PLCControler.py
plcopen/POUVariablesCollector.py
plcopen/XSLTModelQuery.py
plcopen/pou_variables.xslt
plcopen/pou_variables.ysl2
--- a/PLCControler.py	Sat Feb 17 16:42:56 2018 +0100
+++ b/PLCControler.py	Sat Feb 17 23:58:47 2018 +0100
@@ -39,6 +39,7 @@
 from util.TranslationCatalogs import NoTranslate
 from plcopen import *
 from plcopen.InstancesPathCollector import InstancesPathCollector
+from plcopen.POUVariablesCollector import POUVariablesCollector
 from graphics.GraphicCommons import *
 from PLCGenerator import *
 
@@ -209,65 +210,6 @@
             _translate_args([_StringValue] * 5 + [_BoolValue] + [_StringValue], args) +
             [self.GetType(), self.GetTree()])))
 
-# -------------------------------------------------------------------------------
-#            Helpers object for generating pou variable instance list
-# -------------------------------------------------------------------------------
-
-
-def class_extraction(value):
-    class_type = {
-        "configuration": ITEM_CONFIGURATION,
-        "resource": ITEM_RESOURCE,
-        "action": ITEM_ACTION,
-        "transition": ITEM_TRANSITION,
-        "program": ITEM_PROGRAM}.get(value)
-    if class_type is not None:
-        return class_type
-
-    pou_type = POU_TYPES.get(value)
-    if pou_type is not None:
-        return pou_type
-
-    var_type = VAR_CLASS_INFOS.get(value)
-    if var_type is not None:
-        return var_type[1]
-
-    return None
-
-
-class _VariablesTreeItemInfos(object):
-    __slots__ = ["name", "var_class", "type", "edit", "debug", "variables"]
-
-    def __init__(self, *args):
-        for attr, value in zip(self.__slots__, args):
-            setattr(self, attr, value if value is not None else "")
-
-    def copy(self):
-        return _VariablesTreeItemInfos(*[getattr(self, attr) for attr in self.__slots__])
-
-
-class VariablesTreeInfosFactory(object):
-
-    def __init__(self):
-        self.Root = None
-
-    def GetRoot(self):
-        return self.Root
-
-    def SetRoot(self, context, *args):
-        self.Root = _VariablesTreeItemInfos(
-            *([''] + _translate_args(
-                [class_extraction, _StringValue] + [_BoolValue] * 2,
-                args) + [[]]))
-
-    def AddVariable(self, context, *args):
-        if self.Root is not None:
-            self.Root.variables.append(_VariablesTreeItemInfos(
-                *(_translate_args(
-                    [_StringValue, class_extraction, _StringValue] +
-                    [_BoolValue] * 2, args) + [[]])))
-
-
 class InstanceTagName(object):
     """Helpers object for generating instance tagname"""
 
@@ -550,6 +492,7 @@
         self.LastNewIndex = 0
         self.Reset()
         self.InstancesPathCollector = InstancesPathCollector(self)
+        self.POUVariablesCollector = POUVariablesCollector(self)
 
     # Reset PLCControler internal variables
     def Reset(self):
@@ -772,18 +715,6 @@
     def GetPouVariables(self, tagname, debug=False):
         project = self.GetProject(debug)
         if project is not None:
-            factory = VariablesTreeInfosFactory()
-
-            parser = etree.XMLParser()
-            parser.resolvers.add(LibraryResolver(self, debug))
-
-            pou_variable_xslt_tree = etree.XSLT(
-                etree.parse(
-                    os.path.join(ScriptDirectory, "plcopen", "pou_variables.xslt"),
-                    parser),
-                extensions={("pou_vars_ns", name): getattr(factory, name)
-                            for name in ["SetRoot", "AddVariable"]})
-
             obj = None
             words = tagname.split("::")
             if words[0] == "P":
@@ -791,8 +722,7 @@
             elif words[0] != "D":
                 obj = self.GetEditedElement(tagname, debug)
             if obj is not None:
-                pou_variable_xslt_tree(obj)
-                return factory.GetRoot()
+                return self.POUVariablesCollector.Collect(obj, debug)
 
         return None
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plcopen/POUVariablesCollector.py	Sat Feb 17 23:58:47 2018 +0100
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# This file is part of Beremiz.
+# See COPYING file for copyrights details.
+
+from __future__ import absolute_import
+from plcopen.XSLTModelQuery import XSLTModelQuery
+
+def class_extraction(value):
+    class_type = {
+        "configuration": ITEM_CONFIGURATION,
+        "resource": ITEM_RESOURCE,
+        "action": ITEM_ACTION,
+        "transition": ITEM_TRANSITION,
+        "program": ITEM_PROGRAM}.get(value)
+    if class_type is not None:
+        return class_type
+
+    pou_type = POU_TYPES.get(value)
+    if pou_type is not None:
+        return pou_type
+
+    var_type = VAR_CLASS_INFOS.get(value)
+    if var_type is not None:
+        return var_type[1]
+
+    return None
+
+
+class _VariablesTreeItemInfos(object):
+    __slots__ = ["name", "var_class", "type", "edit", "debug", "variables"]
+
+    def __init__(self, *args):
+        for attr, value in zip(self.__slots__, args):
+            setattr(self, attr, value if value is not None else "")
+
+    def copy(self):
+        return _VariablesTreeItemInfos(*[getattr(self, attr) for attr in self.__slots__])
+
+
+class VariablesTreeInfosFactory(object):
+
+    def __init__(self):
+        self.Root = None
+
+    def GetRoot(self):
+        return self.Root
+
+    def SetRoot(self, context, *args):
+        self.Root = _VariablesTreeItemInfos(
+            *([''] + _translate_args(
+                [class_extraction, _StringValue] + [_BoolValue] * 2,
+                args) + [[]]))
+
+    def AddVariable(self, context, *args):
+        if self.Root is not None:
+            self.Root.variables.append(_VariablesTreeItemInfos(
+                *(_translate_args(
+                    [_StringValue, class_extraction, _StringValue] +
+                    [_BoolValue] * 2, args) + [[]])))
+
+
+
+class POUVariablesCollector(XSLTModelQuery):
+    """ object for collecting instances path list"""
+    def __init__(self, controller):
+        XSLTModelQuery.__init__(self,
+                                controller,
+                                "pou_variables.xslt",
+                                [(name, lambda *x : getattr(self.factory, name)(*x)) 
+                                    for name in ["SetRoot", "AddVariable"]])
+
+    def Collect(self, root, debug):
+        self.factory = VariablesTreeInfosFactory()
+        self._process_xslt(root, debug)
+        res = self.factory.GetRoot()
+        self.factory = None
+        return res
+
--- a/plcopen/XSLTModelQuery.py	Sat Feb 17 16:42:56 2018 +0100
+++ b/plcopen/XSLTModelQuery.py	Sat Feb 17 23:58:47 2018 +0100
@@ -36,4 +36,6 @@
 
     def _process_xslt(self, root, debug, **kwargs):
         self.debug = debug
-        return self.xslt(root,**{k:etree.XSLT.strparam(v) for k,v in kwargs.iteritems()})
+        res = self.xslt(root,**{k:etree.XSLT.strparam(v) for k,v in kwargs.iteritems()})
+        # print(self.xslt.error_log)
+        return res
--- a/plcopen/pou_variables.xslt	Sat Feb 17 16:42:56 2018 +0100
+++ b/plcopen/pou_variables.xslt	Sat Feb 17 23:58:47 2018 +0100
@@ -1,20 +1,14 @@
 <?xml version="1.0"?>
-<xsl:stylesheet xmlns:exsl="http://exslt.org/common" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:ppx="http://www.plcopen.org/xml/tc6_0201" xmlns:ns="pou_vars_ns" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" extension-element-prefixes="ns" version="1.0" exclude-result-prefixes="ns">
+<xsl:stylesheet xmlns:exsl="http://exslt.org/common" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:ppx="http://www.plcopen.org/xml/tc6_0201" xmlns:ns="beremiz" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" extension-element-prefixes="ns" version="1.0" exclude-result-prefixes="ns">
   <xsl:output method="xml"/>
   <xsl:template match="text()"/>
   <xsl:template mode="var_class" match="text()"/>
   <xsl:template mode="var_type" match="text()"/>
   <xsl:template mode="var_edit" match="text()"/>
   <xsl:template mode="var_debug" match="text()"/>
-  <xsl:variable name="project">
-    <xsl:copy-of select="document('project')/project/*"/>
-  </xsl:variable>
-  <xsl:variable name="stdlib">
-    <xsl:copy-of select="document('stdlib')/stdlib/*"/>
-  </xsl:variable>
-  <xsl:variable name="extensions">
-    <xsl:copy-of select="document('extensions')/extensions/*"/>
-  </xsl:variable>
+  <xsl:variable name="project" select="ns:GetProject()"/>
+  <xsl:variable name="stdlib" select="ns:GetStdLibs()"/>
+  <xsl:variable name="extensions" select="ns:GetExtensions()"/>
   <xsl:template name="add_root">
     <xsl:param name="class"/>
     <xsl:param name="type"/>
@@ -210,12 +204,10 @@
   <xsl:template mode="var_class" match="*[self::ppx:type or self::ppx:baseType]/ppx:derived">
     <xsl:param name="default_class"/>
     <xsl:variable name="type_name" select="@name"/>
-    <xsl:variable name="pou_infos">
-      <xsl:copy-of select="exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                    exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                    exsl:node-set($extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]"/>
-    </xsl:variable>
+    <xsl:variable name="pou_infos" select="($project|$stdlib|$extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]"/>
     <xsl:choose>
-      <xsl:when test="$pou_infos != ''">
-        <xsl:apply-templates mode="var_class" select="exsl:node-set($pou_infos)"/>
+      <xsl:when test="$pou_infos">
+        <xsl:apply-templates mode="var_class" select="$pou_infos"/>
       </xsl:when>
       <xsl:otherwise>
         <xsl:value-of select="$default_class"/>
@@ -253,11 +245,9 @@
   </xsl:template>
   <xsl:template mode="var_edit" match="*[self::ppx:type or self::ppx:baseType]/ppx:derived">
     <xsl:variable name="type_name" select="@name"/>
-    <xsl:variable name="pou_infos">
-      <xsl:copy-of select="exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]"/>
-    </xsl:variable>
+    <xsl:variable name="pou_infos" select="$project/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]"/>
     <xsl:choose>
-      <xsl:when test="$pou_infos != ''">
+      <xsl:when test="$pou_infos">
         <xsl:text>true</xsl:text>
       </xsl:when>
       <xsl:otherwise>
@@ -273,12 +263,10 @@
   </xsl:template>
   <xsl:template mode="var_debug" match="*[self::ppx:type or self::ppx:baseType]/ppx:derived">
     <xsl:variable name="type_name" select="@name"/>
-    <xsl:variable name="datatype_infos">
-      <xsl:copy-of select="exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                    exsl:node-set($project)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |&#10;                    exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |&#10;                    exsl:node-set($extensions)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name]"/>
-    </xsl:variable>
+    <xsl:variable name="datatype_infos" select="($project|$stdlib|$extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]"/>
     <xsl:choose>
       <xsl:when test="$datatype_infos != ''">
-        <xsl:apply-templates mode="var_debug" select="exsl:node-set($datatype_infos)"/>
+        <xsl:apply-templates mode="var_debug" select="$datatype_infos"/>
       </xsl:when>
       <xsl:otherwise>
         <xsl:text>false</xsl:text>
--- a/plcopen/pou_variables.ysl2	Sat Feb 17 16:42:56 2018 +0100
+++ b/plcopen/pou_variables.ysl2	Sat Feb 17 23:58:47 2018 +0100
@@ -1,7 +1,7 @@
 include yslt_noindent.yml2
 istylesheet xmlns:ppx="http://www.plcopen.org/xml/tc6_0201"
             xmlns:xhtml="http://www.w3.org/1999/xhtml"
-            xmlns:ns="pou_vars_ns" 
+            xmlns:ns="beremiz" 
             extension-element-prefixes="ns" 
             exclude-result-prefixes="ns" {
     
@@ -11,16 +11,11 @@
     template "text()", mode="var_edit";
     template "text()", mode="var_debug";
     
-    variable "project" {
-        copy "document('project')/project/*";
-    }
-    
-    variable "stdlib" {
-        copy "document('stdlib')/stdlib/*";
-    }
-    variable "extensions" {
-        copy "document('extensions')/extensions/*";
-    }
+    variable "project", "ns:GetProject()";
+    
+    variable "stdlib", "ns:GetStdLibs()";
+
+    variable "extensions", "ns:GetExtensions()";
     
     function "add_root" {
         param "class";
@@ -176,14 +171,10 @@
     template "*[self::ppx:type or self::ppx:baseType]/ppx:derived", mode="var_class" {
         param "default_class";
         variable "type_name", "@name";
-        variable "pou_infos" {
-            copy """exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                    exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                    exsl:node-set($extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]""";
-        }
+        variable "pou_infos", "($project|$stdlib|$extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]";
         choose {
-            when "$pou_infos != ''" {
-                apply "exsl:node-set($pou_infos)", mode="var_class";
+            when "$pou_infos" {
+                apply "$pou_infos", mode="var_class";
             }
             otherwise {
                 value "$default_class"
@@ -227,11 +218,9 @@
     
     template "*[self::ppx:type or self::ppx:baseType]/ppx:derived", mode="var_edit" {
         variable "type_name", "@name";
-        variable "pou_infos" {
-            copy "exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]";
-        }
+        variable "pou_infos", "$project/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]";
         choose {
-            when "$pou_infos != ''" > true
+            when "$pou_infos" > true
             otherwise > false
         }
     }
@@ -246,15 +235,10 @@
     
     template "*[self::ppx:type or self::ppx:baseType]/ppx:derived", mode="var_debug" {
         variable "type_name", "@name";
-        variable "datatype_infos" {
-            copy """exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                    exsl:node-set($project)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |
-                    exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |
-                    exsl:node-set($extensions)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name]""";
-        }
+        variable "datatype_infos", "($project|$stdlib|$extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]";
         choose {
             when "$datatype_infos != ''" {
-                apply "exsl:node-set($datatype_infos)", mode="var_debug";
+                apply "$datatype_infos", mode="var_debug";
             }
             otherwise > false
         }