As an aside, in situations such as this one I like to use “data walkers” whenever possible ... search for the keyword walker at http://search.cpan.org and you will see what I mean. (Say, Data::Leaf::Walker ... there are 110 packages today to choose from.) This lets me “let the Walker do the walking” through the now-arbitrary data structure that I have been given, and to call my subroutines only for the elements of interest to me no matter where exactly they happen to be. If the data structure changes, my code still works. Some of these are simple; others more-or-less emulate the approach of “XPath expressions” in XML. While this notion is certainly not of a nature that “you should always do this” – not by any means – it is a useful technique to keep in the back of your pocket-protector.
I used this technique very successfully to winnow through parse-trees that were produced from a nasty collection of SAS® programs, Korn shell scripts, and Tivoli® workload schedules. Truly an ugly project to design and build, but it worked splendidly, thanks in very large part to this technique.