// "HMI:WidgetType|freq:param1:param2@a=.path0@a=path1,path1min,path1max@b=path2#a+b>3"
// widget type="WidgetType" id="blah456" enable_expr="a+b>3" {
// path value=".path0" index=".path0" type="PAGE_LOCAL";
// path value="/path1" index="348" type="HMI_INT" min="path1min" max="path1max" assign="a";
// path value="path4" index="path4" type="HMI_LOCAL" assign=b;
const "pathregex",!"'^(\w+=)?([^,=]+)([-.\w,]*)$'"!;
const "twonewlines", "concat($newline,$newline)";
template "*", mode="parselabel"
const "label","@inkscape:label";
const "desc", "svg:desc";
// add svg:desc field if continuation "\" marker is found at the end of label
const "len","string-length($label)";
const "has_continuation", "substring($label,$len,1)='\\'";
const "full_decl" choose{
when "$has_continuation" {
const "_continuation", "substring-before($desc, $twonewlines)";
const "continuation" choose {
when "$_continuation" value "$_continuation";
value "concat(substring($label,1,$len - 1),translate($continuation,$newline,''))";
otherwise value "$label";
const "declaration", "substring-after($full_decl,'HMI:')";
const "_args", "substring-before($declaration,'@')";
when "$_args" value "$_args";
otherwise value "$declaration";
const "_typefreq", "substring-before($args,':')";
const "typefreq" choose {
when "$_typefreq" value "$_typefreq";
const "freq", "substring-after($typefreq,'|')";
const "_type", "substring-before($typefreq,'|')";
when "$_type" value "$_type";
otherwise value "$typefreq";
if "not(regexp:test($freq,'^[0-9]*(\.[0-9]+)?[smh]?'))" {
error > Widget id:«$id» label:«$full_decl» has wrong syntax of frequency forcing «$freq»
// find "#" + JS expr at the end
const "tail", "substring-after($declaration,'@')";
const "taillen","string-length($tail)";
const "has_enable", "contains($tail, '#')";
value "substring-before($tail,'#')";
const "enable_expr", "substring-after($tail,'#')";
attrib "enable_expr" value "$enable_expr";
foreach "str:split(substring-after($args, ':'), ':')" {
// for stricter syntax checking, this should make error
// if $paths contains "@@" or ends with "@" (empty paths)
foreach "str:split($paths, '@')" {
if "string-length(.) > 0" path {
const "path_match", "regexp:match(.,$pathregex)";
const "pathassign", "substring-before($path_match[2],'=')";
const "pathminmax", "str:split($path_match[4],',')";
const "path", "$path_match[3]";
const "pathminmaxcount", "count($pathminmax)";
error > Widget id:«$id» label:«$full_decl» has wrong syntax
attrib "value" value "$path";
attrib "assign" value "$pathassign";
when "$pathminmaxcount = 2" {
attrib "min" > «$pathminmax[1]»
attrib "max" > «$pathminmax[2]»
when "$pathminmaxcount = 1 or $pathminmaxcount > 2" {
error > Widget id:«$id» label:«$full_decl» has wrong syntax of path section «$pathminmax»
if "$indexed_hmitree" 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
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:«$full_decl» path section «$pathminmax» use min and max on non mumeric value
attrib "index" > «$item/@index»
attrib "type" > «$pathtype»
when "$has_continuation" {
const "_continuation", "substring-after($desc, $twonewlines)";
desc value "$_continuation";
if "$desc" desc value "$desc/text()";
// Templates to generate label back from parsed tree
template "arg", mode="genlabel" > :«@value»
template "path", mode="genlabel" {
if "string-length(@min)>0 or string-length(@max)>0" > ,«@min»,«@max»
template "widget", mode="genlabel" {
apply "arg", mode="genlabel";
apply "path", mode="genlabel";