Coyote's Guide to IDL Programming

Obtaining IDL Structure Tags Recursively

QUESTION: Does anyone have a "recursive" Tag_Names like function? I would like to pass in a structure and get back a string array with members down to the bottom level. For example:

   IDL> input = {a:{m,n}, b:{r,s,t}, c, d, e}
   IDL> output = Recursive_Tag_Names_Function(input)
   IDL> Print, output
        'input.a.m', 'input.a.n', 'input.b.r', 'input.b.s', 'input.b.t',
        'input.c', 'input.d', 'input.e'

ANSWER: It must have been a slow news day, or something, but for some reason this question intrigued me. I thought something like this might be useful for the object programming I am doing.

So here it is. There is a little main-level program below the two program modules that exercises the principle program, Get_Tags. If you just pass the structure to the program, you get all the fields with a "dot" in front of the names. For example,

   IDL> tags = Get_Tags(struct)

returns:

   .one
   .one.two
   .one.two.three

etc. If you want the full name back, pass a second positional parameter that is the root name of the structure. For example,

   IDL> tags = Get_Tags(struct, 'struct')

returns:

   struct.one
   struct.one.two
   struct.one.two.three

Note that the string vector that is actually returned from the Get_Tags function is in all UPPERCASE characters.

   Function All_Tags, structure, rootname

   ; This is a function that recursively searches through
   ; a structure tree, finding ALL of the structure's field names.
   ; It returns a pointer to an array of pointers, each pointing
   ; to the names of structure fields.

   IF N_Elements(rootname) EQ 0 THEN rootname = '.' ELSE $
      rootname = StrUpCase(rootname) + '.'
   names = Tag_Names(structure)
   retValue = Ptr_New(rootname + names)

      ; If any of the fields are structures, report them too.

   FOR j=0,N_Elements(names)-1 DO BEGIN
      ok = Execute('s = Size(structure.' + names[j] + ')')
      IF s[s[0]+1] EQ 8 THEN BEGIN
         newrootname = rootname + names[j]
         theseNames = Call_Function('All_Tags', $
            structure.(j), newrootname)
         retValue = [[retValue],[theseNames]]
      ENDIF
   ENDFOR

   RETURN, retValue
   END
   ;-------------------------------------------------------------------



   FUNCTION Get_Tags, structure, rootname

   ; This function returns the names of all structure fields
   ; in the structure as a string array. The names are given
   ; as valid structure names from the root structure name,
   ; which can be passed in along with the structure itself.

   On_Error, 1

      ; Check parameters.

   CASE N_Params() OF

      0: BEGIN
         Message, 'Structure argument is required.'
         ENDCASE
         
      1: BEGIN
         rootname = ''
         s = Size(structure)
         IF s[s[0]+1] NE 8 THEN $
            Message, 'Structure argument is required.'
         ENDCASE
         
      2: BEGIN
         s = Size(structure)
         IF s[s[0]+1] NE 8 THEN $
            Message, 'Structure argument is required.'
         s = Size(rootname)
         IF s[s[0]+1] NE 7 THEN $
            Message, 'Root Name parameter must be a STRING'
         ENDCASE
         
   ENDCASE

   tags = All_Tags(structure, rootname)

      ; Extract and free the first pointer.

   retval = [*tags[0,0]]
   Ptr_Free, tags[0,0]

      ; Extract and free the the rest of the pointers.
      
   s = Size(tags)
   FOR j=1,s[2]-1 DO BEGIN
      retval = [retval, *tags[0,j]]
      Ptr_Free, tags[0,j]
   ENDFOR
   Ptr_Free, tags

      ; Return the structure names.
      
   RETURN, retval
   END


      ; Main-level program to exercise Get_Tags.

   d = {dog:'spot', cat:'fuzzy'}
   c = {spots:4, animals:d}
   b = {fast:c, slow:-1}
   a = {cars:b, pipeds:c, others:'man'}
   tags = Get_Tags(a)
   s = Size(tags)
   For j=0,s[1]-1 Do Print, tags[j]
   END

Google
 
Web Coyote's Guide to IDL Programming