SVGHMI: Simplification and optimization. func:parselabel becomes a template. svghmi
authorEdouard Tisserant <edouard.tisserant@gmail.com>
Thu, 19 Mar 2020 09:31:07 +0100
branchsvghmi
changeset 2886 6c82fad8be65
parent 2885 f398896b7ebf
child 2887 30cea13267b4
SVGHMI: Simplification and optimization. func:parselabel becomes a template.

All labels are parsed into a global variable containing resulting widget
description as a node-set. func:widget(id) was added for random access to
widget description.
svghmi/detachable_pages.ysl2
svghmi/gen_index_xhtml.xslt
svghmi/hmi_tree.ysl2
svghmi/widgets_common.ysl2
--- a/svghmi/detachable_pages.ysl2	Wed Mar 18 12:06:50 2020 +0100
+++ b/svghmi/detachable_pages.ysl2	Thu Mar 19 09:31:07 2020 +0100
@@ -4,12 +4,13 @@
 // and decide where to cut when removing/attaching 
 // pages elements on page switch
 
-const "hmi_pages", "$hmi_elements[func:parselabel(@inkscape:label)/widget/@type = 'Page']";
+const "hmi_pages_ids", "$parsed_widgets/widget[@type = 'Page']/@id";
+const "hmi_pages", "$hmi_elements[@id = $hmi_pages_ids]";
 
 const "default_page" choose {
     when "count($hmi_pages) > 1" {
         const "Home_page", 
-            "$hmi_pages[func:parselabel(@inkscape:label)/widget/arg[1]/@value = 'Home']";
+            "$hmi_pages[func:widget(@id)/arg[1]/@value = 'Home']";
         choose {
             when "$Home_page" > Home
             otherwise {
@@ -20,7 +21,7 @@
     when "count($hmi_pages) = 0" {
         error "No page defined!";
     }
-    otherwise > «func:parselabel($hmi_pages/@inkscape:label)/widget/arg[1]/@value»
+    otherwise > «func:widget($hmi_pages/@id)/arg[1]/@value»
 }
 
 // returns all directly or indirectly refered elements
@@ -100,16 +101,16 @@
 
 
 template "svg:*", mode="page_desc" {
-    const "desc", "func:parselabel(@inkscape:label)/widget";
+    const "desc", "func:widget(@id)";
     const "page", ".";
     const "p", "$geometry[@Id = $page/@id]";
 
     const "page_all_elements", "func:all_related_elements($page)";
 
-    const "all_page_widgets","$hmi_elements[@id = $page_all_elements/@id and @id != $page/@id][not(func:parselabels(ancestor::svg:*)/widget/@type = 'ForEach')]";
+    const "all_page_widgets","$hmi_elements[@id = $page_all_elements/@id and @id != $page/@id]";
 
     const "page_relative_widgets",
-        "$all_page_widgets[func:is_descendant_path(func:parselabel(@inkscape:label)/widget/path/@value, $desc/path/@value)]";
+        "$all_page_widgets[func:is_descendant_path(func:widget(@id)/path/@value, $desc/path/@value)]";
 
     // Take closest ancestor in detachable_elements
     // since nested detachable elements are filtered out
--- a/svghmi/gen_index_xhtml.xslt	Wed Mar 18 12:06:50 2020 +0100
+++ b/svghmi/gen_index_xhtml.xslt	Thu Mar 19 09:31:07 2020 +0100
@@ -73,8 +73,8 @@
       </xsl:with-param>
     </xsl:apply-templates>
   </xsl:template>
-  <func:function name="func:parselabel">
-    <xsl:param name="label"/>
+  <xsl:template mode="parselabel" match="*">
+    <xsl:variable name="label" select="@inkscape:label"/>
     <xsl:variable name="description" select="substring-after($label,'HMI:')"/>
     <xsl:variable name="_args" select="substring-before($description,'@')"/>
     <xsl:variable name="args">
@@ -98,51 +98,48 @@
         </xsl:otherwise>
       </xsl:choose>
     </xsl:variable>
-    <xsl:variable name="ast">
-      <xsl:if test="$type">
-        <widget>
-          <xsl:attribute name="type">
-            <xsl:value-of select="$type"/>
-          </xsl:attribute>
-          <xsl:for-each select="str:split(substring-after($args, ':'), ':')">
-            <arg>
+    <xsl:if test="$type">
+      <widget>
+        <xsl:attribute name="id">
+          <xsl:value-of select="@id"/>
+        </xsl:attribute>
+        <xsl:attribute name="type">
+          <xsl:value-of select="$type"/>
+        </xsl:attribute>
+        <xsl:for-each select="str:split(substring-after($args, ':'), ':')">
+          <arg>
+            <xsl:attribute name="value">
+              <xsl:value-of select="."/>
+            </xsl:attribute>
+          </arg>
+        </xsl:for-each>
+        <xsl:variable name="paths" select="substring-after($description,'@')"/>
+        <xsl:for-each select="str:split($paths, '@')">
+          <xsl:if test="string-length(.) &gt; 0">
+            <path>
               <xsl:attribute name="value">
                 <xsl:value-of select="."/>
               </xsl:attribute>
-            </arg>
-          </xsl:for-each>
-          <xsl:variable name="paths" select="substring-after($description,'@')"/>
-          <xsl:for-each select="str:split($paths, '@')">
-            <xsl:if test="string-length(.) &gt; 0">
-              <path>
-                <xsl:attribute name="value">
-                  <xsl:value-of select="."/>
+              <xsl:variable name="path" select="."/>
+              <xsl:variable name="item" select="$indexed_hmitree/*[@hmipath = $path]"/>
+              <xsl:if test="count($item) = 1">
+                <xsl:attribute name="index">
+                  <xsl:value-of select="$item/@index"/>
                 </xsl:attribute>
-                <xsl:variable name="path" select="."/>
-                <xsl:variable name="item" select="$indexed_hmitree/*[@hmipath = $path]"/>
-                <xsl:if test="count($item) = 1">
-                  <xsl:attribute name="index">
-                    <xsl:value-of select="$item/@index"/>
-                  </xsl:attribute>
-                </xsl:if>
-              </path>
-            </xsl:if>
-          </xsl:for-each>
-        </widget>
-      </xsl:if>
-    </xsl:variable>
-    <func:result select="exsl:node-set($ast)"/>
-  </func:function>
-  <func:function name="func:parselabels">
-    <xsl:param name="nodes"/>
-    <xsl:choose>
-      <xsl:when test="$nodes">
-        <func:result select="func:parselabel($nodes[1]/@inkscape:label)&#10;                      | func:parselabels($nodes[position()!=1])"/>
-      </xsl:when>
-      <xsl:otherwise>
-        <func:result select="/.."/>
-      </xsl:otherwise>
-    </xsl:choose>
+              </xsl:if>
+            </path>
+          </xsl:if>
+        </xsl:for-each>
+      </widget>
+    </xsl:if>
+  </xsl:template>
+  <xsl:variable name="_parsed_widgets">
+    <xsl:apply-templates mode="parselabel" select="$hmi_elements"/>
+  </xsl:variable>
+  <xsl:variable name="parsed_widgets" select="exsl:node-set($_parsed_widgets)"/>
+  <func:function name="func:widget">
+    <xsl:param name="id"/>
+    <func:result select="$parsed_widgets/widget[@id = $id]"/>
   </func:function>
   <xsl:template mode="testtree" match="*">
     <xsl:param name="indent" select="''"/>
@@ -173,6 +170,12 @@
     <xsl:text>Indexed HMI tree
 </xsl:text>
     <xsl:apply-templates mode="testtree" select="$indexed_hmitree"/>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>Parsed Widgets
+</xsl:text>
+    <xsl:copy-of select="_parsed_widgets"/>
+    <xsl:apply-templates mode="testtree" select="$parsed_widgets"/>
   </xsl:template>
   <xsl:variable name="geometry" select="ns:GetSVGGeometry()"/>
   <xsl:template name="debug_geometry">
@@ -239,11 +242,12 @@
     <xsl:variable name="candidates" select="$geometry[@Id != $elt/@id]"/>
     <func:result select="$candidates[(@Id = $groups/@id and (func:intersect($g, .) = 9)) or &#10;                          (not(@Id = $groups/@id) and (func:intersect($g, .) &gt; 0 ))]"/>
   </func:function>
-  <xsl:variable name="hmi_pages" select="$hmi_elements[func:parselabel(@inkscape:label)/widget/@type = 'Page']"/>
+  <xsl:variable name="hmi_pages_ids" select="$parsed_widgets/widget[@type = 'Page']/@id"/>
+  <xsl:variable name="hmi_pages" select="$hmi_elements[@id = $hmi_pages_ids]"/>
   <xsl:variable name="default_page">
     <xsl:choose>
       <xsl:when test="count($hmi_pages) &gt; 1">
-        <xsl:variable name="Home_page" select="$hmi_pages[func:parselabel(@inkscape:label)/widget/arg[1]/@value = 'Home']"/>
+        <xsl:variable name="Home_page" select="$hmi_pages[func:widget(@id)/arg[1]/@value = 'Home']"/>
         <xsl:choose>
           <xsl:when test="$Home_page">
             <xsl:text>Home</xsl:text>
@@ -257,7 +261,7 @@
         <xsl:message terminate="yes">No page defined!</xsl:message>
       </xsl:when>
       <xsl:otherwise>
-        <xsl:value-of select="func:parselabel($hmi_pages/@inkscape:label)/widget/arg[1]/@value"/>
+        <xsl:value-of select="func:widget($hmi_pages/@id)/arg[1]/@value"/>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:variable>
@@ -321,12 +325,12 @@
     <func:result select="string-length($ancest) &gt; 0 and starts-with($descend,$ancest)"/>
   </func:function>
   <xsl:template mode="page_desc" match="svg:*">
-    <xsl:variable name="desc" select="func:parselabel(@inkscape:label)/widget"/>
+    <xsl:variable name="desc" select="func:widget(@id)"/>
     <xsl:variable name="page" select="."/>
     <xsl:variable name="p" select="$geometry[@Id = $page/@id]"/>
     <xsl:variable name="page_all_elements" select="func:all_related_elements($page)"/>
-    <xsl:variable name="all_page_widgets" select="$hmi_elements[@id = $page_all_elements/@id and @id != $page/@id][not(func:parselabels(ancestor::svg:*)/widget/@type = 'ForEach')]"/>
-    <xsl:variable name="page_relative_widgets" select="$all_page_widgets[func:is_descendant_path(func:parselabel(@inkscape:label)/widget/path/@value, $desc/path/@value)]"/>
+    <xsl:variable name="all_page_widgets" select="$hmi_elements[@id = $page_all_elements/@id and @id != $page/@id]"/>
+    <xsl:variable name="page_relative_widgets" select="$all_page_widgets[func:is_descendant_path(func:widget(@id)/path/@value, $desc/path/@value)]"/>
     <xsl:variable name="required_detachables" select="func:sumarized_elements($page_all_elements)/&#10;           ancestor-or-self::*[@id = $detachable_elements/@id]"/>
     <xsl:text>  "</xsl:text>
     <xsl:value-of select="$desc/arg[1]/@value"/>
@@ -539,7 +543,7 @@
     </xsl:for-each>
   </xsl:template>
   <xsl:template mode="hmi_elements" match="svg:*">
-    <xsl:variable name="widget" select="func:parselabel(@inkscape:label)/widget"/>
+    <xsl:variable name="widget" select="func:widget(@id)"/>
     <xsl:variable name="eltid" select="@id"/>
     <xsl:text>  "</xsl:text>
     <xsl:value-of select="@id"/>
--- a/svghmi/hmi_tree.ysl2	Wed Mar 18 12:06:50 2020 +0100
+++ b/svghmi/hmi_tree.ysl2	Thu Mar 19 09:31:07 2020 +0100
@@ -63,8 +63,8 @@
 //      path value="path2";
 //  }
 //
-def "func:parselabel" {
-    param "label";
+template "*", mode="parselabel" {
+    const "label","@inkscape:label";
     const "description", "substring-after($label,'HMI:')";
 
     const "_args", "substring-before($description,'@')";
@@ -79,7 +79,8 @@
         otherwise value "$args";
     }
 
-    const "ast" if "$type" widget {
+    if "$type" widget {
+        attrib "id" > «@id»
         attrib "type" > «$type»
         foreach "str:split(substring-after($args, ':'), ':')" {
             arg {
@@ -97,22 +98,17 @@
             }
         }
     }
-
-    result "exsl:node-set($ast)";
 }
 
-def "func:parselabels" {
-    param "nodes"; 
-    choose{
-        when "$nodes"{
-            result """func:parselabel($nodes[1]/@inkscape:label)
-                      | func:parselabels($nodes[position()!=1])""";
-        }otherwise{
-            result "/..";
-        }
-    }
+const "_parsed_widgets" apply "$hmi_elements", mode="parselabel";
+const "parsed_widgets","exsl:node-set($_parsed_widgets)";
+
+def "func:widget" {
+    param "id";
+    result "$parsed_widgets/widget[@id = $id]";
 }
 
+
 // Debug data
 template "*", mode="testtree"{
     param "indent", "''";
@@ -129,5 +125,9 @@
     |
     | Indexed HMI tree
     apply "$indexed_hmitree", mode="testtree";
+    |
+    | Parsed Widgets
+    copy "_parsed_widgets";
+    apply "$parsed_widgets", mode="testtree";
 }
 !debug_output_calls.append("debug_hmitree")
--- a/svghmi/widgets_common.ysl2	Wed Mar 18 12:06:50 2020 +0100
+++ b/svghmi/widgets_common.ysl2	Thu Mar 19 09:31:07 2020 +0100
@@ -12,7 +12,7 @@
 };
 
 template "svg:*", mode="hmi_elements" {
-    const "widget", "func:parselabel(@inkscape:label)/widget";
+    const "widget", "func:widget(@id)";
     const "eltid","@id";
     |   "«@id»": {
     |     type: "«$widget/@type»",