// hmi_tree.ysl2 // HMI Tree computed from VARIABLES.CSV in svghmi.py const "hmitree", "ns:GetHMITree()"; const "_categories" { noindex > HMI_PLC_STATUS noindex > HMI_CURRENT_PAGE } const "categories", "exsl:node-set($_categories)"; // HMI Tree Index const "_indexed_hmitree" apply "$hmitree", mode="index"; const "indexed_hmitree", "exsl:node-set($_indexed_hmitree)"; emit "preamble:hmi-tree" { | var hmi_hash = [«$hmitree/@hash»]; | | var heartbeat_index = «$indexed_hmitree/*[@hmipath = '/HEARTBEAT']/@index»; | | var hmitree_types = [ foreach "$indexed_hmitree/*" | /* «@index» */ "«substring(local-name(), 5)»"`if "position()!=last()" > ,` | ]; | | var hmitree_paths = [ foreach "$indexed_hmitree/*" | /* «@index» */ "«@hmipath»"`if "position()!=last()" > ,` | ]; | } template "*", mode="index" { param "index", "0"; param "parentpath", "''"; const "content" { const "path" choose { when "count(ancestor::*)=0" > / when "count(ancestor::*)=1" > /«@name» otherwise > «$parentpath»/«@name» } choose { when "not(local-name() = $categories/noindex)" { xsl:copy { attrib "index" > «$index» attrib "hmipath" > «$path» foreach "@*" xsl:copy; } apply "*[1]", mode="index"{ with "index", "$index + 1"; with "parentpath" > «$path» } } otherwise { apply "*[1]", mode="index"{ with "index", "$index"; with "parentpath" > «$path» } } } } copy "$content"; apply "following-sibling::*[1]", mode="index" { with "index", "$index + count(exsl:node-set($content)/*)"; with "parentpath" > «$parentpath» } } // Parses: // "HMI:WidgetType:param1:param2@path1,path1min,path1max@path2" // // Into: // widget type="WidgetType" id="blah456" { // arg value="param1"; // arg value="param2"; // path value=".path1" index=".path1" min="path1min" max="path1max" type="PAGE_LOCAL"; // path value="/path1" index="348" type="HMI_INT"; // path value="path4" index="path4" type="HMI_LOCAL"; // } // template "*", mode="parselabel" { const "label","@inkscape:label"; const "id","@id"; const "description", "substring-after($label,'HMI:')"; const "_args", "substring-before($description,'@')"; const "args" choose { when "$_args" value "$_args"; otherwise value "$description"; } const "_type", "substring-before($args,':')"; const "type" choose { when "$_type" value "$_type"; otherwise value "$args"; } if "$type" widget { attrib "id" > «$id» attrib "type" > «$type» foreach "str:split(substring-after($args, ':'), ':')" { arg { attrib "value" > «.» } } const "paths", "substring-after($description,'@')"; foreach "str:split($paths, '@')" { if "string-length(.) > 0" path { const "pathminmax", "str:split(.,',')"; const "path", "$pathminmax[1]"; const "pathminmaxcount", "count($pathminmax)"; attrib "value" > «$path» choose { when "$pathminmaxcount = 3" { attrib "min" > «$pathminmax[2]» attrib "max" > «$pathminmax[3]» } when "$pathminmaxcount = 2" { error > Widget id:«$id» label:«$label» has wrong syntax of path section «$pathminmax» } } choose { when "regexp:test($path,'^\.[a-zA-Z0-9_]+$')" { attrib "type" > PAGE_LOCAL } when "regexp:test($path,'^[a-zA-Z0-9_]+$')" { attrib "type" > HMI_LOCAL } otherwise { const "item", "$indexed_hmitree/*[@hmipath = $path]"; const "pathtype", "local-name($item)"; if "$pathminmaxcount = 3 and not($pathtype = 'HMI_INT' or $pathtype = 'HMI_REAL')" { error > Widget id:«$id» label:«$label» path section «$pathminmax» use min and max on non mumeric value } if "count($item) = 1" { attrib "index" > «$item/@index» attrib "type" > «$pathtype» } } } } } } } const "_parsed_widgets" { widget type="VarInitPersistent" { arg value="0"; path value="lang"; } apply "$hmi_elements", mode="parselabel"; } const "parsed_widgets","exsl:node-set($_parsed_widgets)"; def "func:widget" { param "id"; result "$parsed_widgets/widget[@id = $id]"; } def "func:is_descendant_path" { param "descend"; param "ancest"; // TODO : use HMI tree to answer more accurately result "string-length($ancest) > 0 and starts-with($descend,$ancest)"; } def "func:same_class_paths" { param "a"; param "b"; const "class_a", "$indexed_hmitree/*[@hmipath = $a]/@class"; const "class_b", "$indexed_hmitree/*[@hmipath = $b]/@class"; result "$class_a and $class_b and $class_a = $class_b"; } // Debug data template "*", mode="testtree"{ param "indent", "''"; > «$indent» «local-name()» foreach "@*" > «local-name()»="«.»" > \n apply "*", mode="testtree" { with "indent" value "concat($indent,'>')" }; } emit "debug:hmi-tree" { | Raw HMI tree apply "$hmitree", mode="testtree"; | | Indexed HMI tree apply "$indexed_hmitree", mode="testtree"; | | Parsed Widgets copy "_parsed_widgets"; apply "$parsed_widgets", mode="testtree"; }