2013-10-31

Getting Started with Tcl in FME: List Attribute Manipulation in TclCaller

Previous: Startup / Shutdown Script

A list attribute contains multiple values under the same name, each element of a list is distinguished from others by its index. The index is usually 0-based sequential number quoted by braces (curly brackets); it's a part of the attribute name indicating an element.
Names of individual list elements are typically represented like these:
_list{0}, _list{1}, _list{2} ...
_list{0}.sub, _list{1}.sub, _list{2}.sub ...

Every element can be treated as well as a non-list attribute using its name (including index) in the Tcl script. And also, since the name contains an index, repetitive processing commands (for, foreach etc.) would be effective in many cases.
Here I'll give some Tcl procedure examples for the TclCaller.

Convert Multiple Attributes to a List Attribute
This procedure collects 3 non-list attribute values and create a list attribute named _code which contains original 3 attribute values as its elements. This functionality is similar to the ListPopulator transformer.
-----
proc multiAttributesToList {} {
  set i 0
  foreach name {"CODE_A" "CODE_B" "CODE_C"} {
    FME_SetAttribute "_code{$i}" [FME_GetAttribute $name]
    incr i
  }
}
-----

Concatenate List Elements
This procedure concatenates every element in a list attribute named _list, and returns the result as a comma separated string. Similar to the ListConcatenator transformer.
-----
proc concatList {} {
  set elements {}
  for {set i 0} {[FME_AttributeExists "_list{$i}"]} {incr i} {
    lappend elements [FME_GetAttribute "_list{$i}"]
  }
  return [join $elements {,}]
}
-----

Calculate Basic Statistics of List Elements
This procedure calculates sum, minimum, maximum and average of elements of a list attribute named _src, sets the results as new non-list attributes, and returns number of the elements. Assume all elements of the list are numeric representation.
-----
proc calcBasicStatistics {} {
  for {set count 0} {[FME_AttributeExists "_src{$count}"]} {incr count} {
    set val [FME_GetAttribute "_src{$count}"]
    if {$count == 0} {
      set sum [set min [set max $val]]
    } else {
      set sum [expr $sum + $val]
      if {$val < $min} {set min $val}
      if {$max < $val} {set max $val}
    }
  }
  if {0 < $count} {
    FME_SetAttribute "_sum" $sum
    FME_SetAttribute "_min" $min
    FME_SetAttribute "_max" $max
    FME_SetAttribute "_ave" [expr double($sum) / $count]
  }
  return $count
}
-----

"Getting Started with Tcl in FME" series ends here. My Tcl skill made progress a little???

"Getting Started with Tcl in FME" Titles
TclCaller
AttributeCreator
Other Transformers
Scripted Parameter
Startup / Shutdown Script
List Attribute Manipulation in TclCaller *this post

4 comments:

  1. Hi Takshi,

    Funny, i was looking for list manipulation and see it's you...again :)

    Anyway, your first one should be:

    proc multiAttributesToList {} {
    set i 0
    foreach name {"CODE_A" "CODE_B" "CODE_C"} {
    FME_SetAttribute "_code{$i}" $name
    incr i
    }
    }


    $name instead of [FME_GetAttribute $name]

    ReplyDelete
  2. Hi Takashi,

    It's me again, Gio from FME forum.

    I have another post for you concerning reading list objects with FME macrocommand.

    The listname should not be quoted.
    Also if the list is not simple, but has elements. Then to test, for existance, you need to test for the element(s)

    for instance a list _list with 2 elements
    _list{}.Dog
    _list{}.Cat
    cannot be tested with _list{$i} but only _list{$i}.Dog or _list{$i}.Cat
    If nested more and the attribute u need is deeper it goes on _list{}.Dog{}.Color etc.
    (It is possible in tcl to make non balanced list with empty elemenst of course, i one insists)


    proc concatList {} {
    set elements {}
    for {set i 0} {[FME_AttributeExists _list{$i}]} {incr i} {
    lappend elements [FME_GetAttribute _list{$i}]
    }
    return [join $elements {,}]
    }




    ReplyDelete
  3. Hi, welcome :) I'm assuming that input feature has 3 non-list attributes called "CODE_A", "CODE_B", and "CODE_C". The procedure populates values of those attributes into a list attribute. So I'm using "FME_GetAttribute" procedure to retrieve attribute value.

    ReplyDelete
  4. Gio, thank you for the inputs.
    As you say, quotation of list names is not essential in the case where the names don't contain white spaces. But I prefer to quote always feature attribute names (both non-list and list) in Tcl scripts, so that those are noticeable. It's my personal guideline for Tcl scripting.
    Regarding non-simple list (complex list, nested list), you are right. There could be irregular lists.
    FME_GetAttribute procedure just returns an empty string if specified attribute doesn't exist, i.e. "missing". So it's necessary to test if the list element exists when you have to distinguish an empty string from "missing".

    ReplyDelete