http://qs1969.pair.com?node_id=507777

sara2005 has asked for the wisdom of the Perl Monks concerning the following question:

I am using Perl/CGI in Apache to create some dynamic web pages by reading data from flat files.. Below is a problem I am facing and would appreciate any help from the experts..

I read a data file as shown below and store the contents in an Array of Hashes (AoH)

File1: --------------------- Page = 1 <Start> VarName = name1 Value = value1 Min = min1 Max = max1 <End> <Start> VarName = name2 Value = value2 Min = min2 <End> etc.. etc. Page = 2 <Start> VarName = nam1 Value = val1 <End> <Start> VarName = nam2 Value = val2 Min = mn2 <End> --------------

Note that each hash has been initialized with a standard set of 'key's and after reading the file, only the available keys are populated with a value. after I am done reading the file in an AoH, this is how it looks using Data::Dumper.

[ { 'PageNum'=>1, 'VarName' => 'name1', 'Value' => ' value1', 'Min' => ' min1', 'Max' => ' max1', 'Mod' => ' ' }, { 'PageNum'=>1, 'VarName' => 'name2', 'Value' => ' value2', 'Min' => ' min2', 'Max' => ' ', 'Mod' => ' ' }, etc.. etc.. { 'PageNum'=>2, 'VarName' => 'nam1', 'Value' => ' val1', 'Min' => ' ', 'Max' => ' ', 'Mod' => ' ' }, { 'PageNum'=>2, 'VarName' => 'nam2', 'Value' => ' val2', 'Min' => ' mn2', 'Max' => ' ', 'Mod' => ' ' }, etc..etc.. ]

Now, my CGI code prints out a multipage html page in the following format using the AoH:-

------------- <html><head><title>test</title></head> <body bgcolor="white"> <table border="0"><tr><td><b>Page num:</b></td> <td><select name="page +" size="1" onchange="submitform('Go')"> <option value="1">1</option> <option value="2">2</option> </select> </td> </tr> </table><br /> <table cellpadding="2" id="panel" cellspacing="0" border="1"> <tr align="LEFT"> <th bgcolor="cyan">Variable</th> <th bgcolor="cyan">Min value</th> <th bgcolor="cyan">Value</th> <th bgcolor="cyan">Max Value</th> </tr> <tr valign="TOP" align="LEFT"> <td ><a>name1</a></td> <td ><input type="hidden" name="min1" value="min1" /><a>min1 </a></td> + <td ><input type="input" name="value1" value="value1" /><a></a></td> <td ><input type="hidden" name="max1" value="max1" /><a>max1</a></td> </tr> <tr valign="TOP" align="LEFT"> <td ><a>name2</a></td> <td ><input type="hidden" name="min2" value="min2" /><a>min2 </a></td> + <td ><input type="input" name="value2" value="value2" /><a></a></td> <td ><input type="hidden" name="" value="" /><a></a></td> </tr> </table> </form><center /> </body> </html> --------

The idea is , no matter how many pages are there in the flat file, the inputs pertaining to a selected 'page num' alone will be shown in a page. When the user selects a different page, those inputs listed for the selected page will be shown.

Now, I have a problem when I want to edit a given variable in a given page. The requirement is :-

1) I need to keep track of all the variables that have changed (possibly in the same flat file format) and

2) display the modified variable values, if the user selects a page he had modified few minutes back.

First, I thought about using session management but it only saves the variables and values for a given page (in var=val format). If I have 10 or more pages, it might get cumbersome to manage in this method.

Second, I thought about passing the array of hashes from one page to another but it seems unlikely (not sure though!!! any suggestion on this??)

Finally, I have decided to make a copy of the original flat file and read from the 'copy' to create the input pages. Now, when a value is edited in a given page, I am planning to use a perl script to open the 'copy', go to the appropriate variable that has to be modified and change the value. In this way, I can keep modifying the values and at the same time display the values to the user, if he returns back to the same page within few minutes. Also, by doing a diff with the original, I will be able to get the list of variables that have changed.

Is this is a good approach? Is there any other method that would simplify this task?

Please provide your valuable comments.

Replies are listed 'Best First'.
Re: web-interface using data from flat files
by Aristotle (Chancellor) on Nov 11, 2005 at 17:08 UTC

    Using a flat file doesn’t sound like a good idea. (It rarely is.) I would suggest using a DBM file instead. Using Storable or something like MLDBM or DBM::Deep you could then store arrayrefs in the keys, and thus keep a list of all values ever set on any key.

    Makeshifts last the longest.

      Unfortunately, I don't have any control over the flat file I get to build the user interface. My part is limited to reading the flat file, building the interface and sending back the changes in the same flat file format.

      Also, there is no database involved in the whole process.

      I am going to read thru the links you have suggested but decided to give a little more info on why I use the flat files.

        Ah. Then your chosen approach with a copy of the file probably makes the most sense. I’d tell whoever is telling you to do it this way that their approach doesn’t make a lot of sense, though.

        Makeshifts last the longest.

Re: web-interface using data from flat files
by wfsp (Abbot) on Nov 11, 2005 at 21:09 UTC

    How many users could be updating the data at the same time?

    How big is the flatfile? If it is fairly small (e.g. less than 2k records) I think the flat file arrangement will be fine.

    I have a keyword search app that uses CGI::Session. The results are stored in a hash and the hash, along with a page number, is stored in a session. 10 results/page are displayed. If the user requests next or back the script is able to send the next or previous results.

    In your case you could check the data submitted by the form, update the hash, create a new session (including the page number) and display the appropriate page.

    You could update/rewrite the data file at the same time (bearing in mind the questions above).

    I'm a bit curious about your html. There doesn't appear to be an opening form tag. What are those anchor tags (<a></a>) doing?

    How do you generate the html, how do you display the values from your hash?

    More questions than answers I'm afraid :-) Good luck!

      fortunately, the system has been set-up such that only one user will be working with one file at a time.

      I am afraid the file size is more than 20kb for maxcase

      I am curious to know how you pass Hashes of Hashes (HoH) from one page to another. Can you provide little more details?

      The html i have shown is only a portion of the complete code.. I may have deleted few unknowingly as I meant to just give a glimpse of what i did. As I mentioned earlier, I read the data file, store the data in AoH, then for the selected page no, I churn out html rows with Varname (which is what you see in anchor tags as the intent was to show the variable name to the user), Min, Value and Max. I generate the html codes using cgi.pm module here are few lines on how I generate the html using cgi.pm :-

      AoH is the array of hashes which holds the data read from the flat file

      @required will hold the all the array index that corresponds to the selected page. for example, if you take the sample data file I have given, if user selects pagenum as 1 , then I have a logic to store 0 and 1 to @required. If the user selects pagenum as 2, then 2 and 3 are stored in @required. Then, I use that in a for loop to go to each of the array and print the elements I need from the hash.

      ... foreach $ii (@required) { ... .. $query->a( $AoH[$ii]{'VarName'}), $query->hidden( -name=>'min', -value=>$AoH[$ii]{'Min'}). $query->a($AoH[$ii]{'Min'}), ... etc.... ... }

        Apologies for the delay in getting back to you.

        The only state information you need to maintain is the current page. Using this you know which data to send to the browser and which to write back to disk. Here is one approach.

        It uses CGI::Session (but a hidden field could be used). It also uses HTML::Template.

        If you decided to try it be sure to create a dir called 'tmp' in the same dir as the script (used by CGI::Session). It won't work otherwise.

        Also, I changed the structure (see below) to a HoHoH. This method alows a 'page' full of data to be easily extracted/displayed/written back to disk.

        The HTML is not pretty (!) and will of course need attention. For the sake of this demo I have used a 'back' and 'next' button to move between the pages.