I've recently (6 months ago) created just such an application. My approach was to create a simple template engine that supports 3 kinds of "tags". The template engine will read a template file looking for these tags. When a tag is found, the text for the tag is replaced by a some value (perhaps sourced from a database). The text around the tags is simply echoed out to a file or stdout.
The three types of tags are:
* Simple text replacement.
* A tag with an associated callback.
* A Command tag.
As stated before the simple tag is simply a text replace for the tag with a new value. Optionally, a callback can be implemented to perform some action as a result of encountering the tag such as a formatting the value or performing a calculation. The command tag is a little special. It has a beginning and an ending. The text between is considered a "sub template" and a callback is associated with the command. This is how I implement things like looping.
The main idea of this approach is to build the template file in HTML in the first place, embed tags in the HTML, and separate the process of obtaining the data from the actual rendering of the template. The engine it self could also be called an "Event Based Parser" if that helps.
One other feature that I implemented in this template system was to make the whitespace around the tags optionally significant. Not important for HTML reports but I can "visually" build plain text reports using a text editor when needed.
The solution weighs in at about 800 lines of Perl and is built with OOP design. So, to answer your question, you may want to consider a template solution. Whether you roll your own solution like I did or use an existing template solution, I would consider this approach both viable and effective.