http://www.perlmonks.org?node_id=927790

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

I have written a CGI perl script to communicate to Rational ClearQuest to fetch some data and display it on the screen. I am able to do this but I want to capture the data fetched from ClearQuest to be stored in some variable and later I will use some looping to print the values on the screen. The reason I want to do this because I am also printing a check boxes at the begining of every row. I have a button to do certain action based on the values selected through check boxes. There can be only one or multiple check box selection and depending upon selected check boxes I want to pass the selected values to a perl script and execute that script in backgroud when user clicks on button.

I don't know how to store the data returned by ClearQuest into a variable. If I declare Variable inside the while loop which is retriving ClearQuest data the variable will only store most recent data (i.e. last value fatched). Can anyone please help me out to get this resolved? I have given my code below.

#!C:\Program Files\IBM\RationalSDLC\ClearQuest\CQperl.exe use CGI::Carp qw(fatalsToBrowser); use CQPerlExt; # for ClearQuest API access my ($sessionObj) = CQSession::Build(); my ($workSpace) = ""; $sessionObj->UserLogon("user", "passwd\$", "CQDB", ""); ########################################################### # Create the query to find ReleaseForm records ########################################################### my $queryDef = $sessionObj->BuildQuery("Environment"); # select the fields that you want in the report $queryDef->BuildField("Environment"); $queryDef->BuildField("Release"); $queryDef->BuildField("Project"); $queryDef->BuildField("VLS_Name"); $queryDef->BuildField("AppServerName"); $queryDef->BuildField("State"); $queryDef->BuildField("URL"); my ($FilterNode1) = $queryDef->BuildFilterOperator($CQPerlExt::CQ_BOOL +_OP_AND); $FilterNode1->BuildFilter("Release", $CQPerlExt::CQ_COMP_OP_EQ, ["$R +elease"]); $FilterNode1->BuildFilter("Environment", $CQPerlExt::CQ_COMP_OP_EQ, +["$Environment"]); $FilterNode1->BuildFilter("State", $CQPerlExt::CQ_COMP_OP_EQ, ["Acti +ve"]); $FilterNode1->BuildFilter("Project", $CQPerlExt::CQ_COMP_OP_NEQ, ["I +nfoAdvantage Baseline"]); $FilterNode1->BuildFilter("Project", $CQPerlExt::CQ_COMP_OP_NEQ, ["I +nfoAdvantage Platinum"]); $FilterNode1->BuildFilter("Project", $CQPerlExt::CQ_COMP_OP_NEQ, ["I +nfoAdvantage Custom"]); $FilterNode1->BuildFilter("Project", $CQPerlExt::CQ_COMP_OP_NEQ, ["P +B Baseline"]); # Create sort types and sort orders my $queryFieldDefs = $queryDef->GetQueryFieldDefs(); $hostname = $queryFieldDefs->ItemByName("Release"); $hostname->SetSortType($CQPerlExt::CQ_SORT_ASC); $hostname->SetSortOrder(1); my $resultSet = $sessionObj->BuildResultSet($queryDef); # create our + result set $resultSet->EnableRecordCount(); # execute the query and populate the result set $resultSet->Execute(); # go to the first row of the result set $status = $resultSet->MoveNext(); # while we have another row in the result set while ($status == $CQPerlExt::CQ_SUCCESS) { my $Environment = $resultSet->GetColumnValue(1); my $Release = $resultSet->GetColumnValue(2); my $Project = $resultSet->GetColumnValue(3); my $VLS_Name = $resultSet->GetColumnValue(4); my $AppServerName = $resultSet->GetColumnValue(5); my $State = $resultSet->GetColumnValue(6); my $URL = $resultSet->GetColumnValue(7); print <<END_HTML; <table border="1" cellpadding="8" bgcolor="#CCD6F5"> <tr> <td><input type="checkbox" value="$VLSName"/></td> <td>$Release</td> <td>$Environment</td> <td width="160">$Project</td> <td width="430"><a href="$URL">$URL</a></td> </tr> </table> END_HTML # next row in result set $status = $resultSet->MoveNext; } print <<END_HTML; <br><input type="submit" value="Bounce"/> </form> END_HTML CQSession::Unbuild($sessionObj);

Replies are listed 'Best First'.
Re: Capture output of a while loop into a variable
by onelesd (Pilgrim) on Sep 26, 2011 at 05:24 UTC

    There's quite a few ways to skin this cat, some of them better than doing it in the while loop, but since you said you want to do it in your while loop, you can do that this way without changing your existing code:

    my @save4later ; while ($status == $CQPerlExt::CQ_SUCCESS) { my $Environment = $resultSet->GetColumnValue(1); my $Release = $resultSet->GetColumnValue(2); my $Project = $resultSet->GetColumnValue(3); my $VLS_Name = $resultSet->GetColumnValue(4); my $AppServerName = $resultSet->GetColumnValue(5); my $State = $resultSet->GetColumnValue(6); my $URL = $resultSet->GetColumnValue(7); push @save4later, { Environment => $Environment, Release => $Release, Project => $Project, VLS_Name => $VLS_Name, AppServerName => $AppServerName, State => $State, URL => $URL, } ; print <<END_HTML; <table border="1" cellpadding="8" bgcolor="#CCD6F5"> <tr> <td><input type="checkbox" value="$VLSName"/></td> <td>$Release</td> <td>$Environment</td> <td width="160">$Project</td> <td width="430"><a href="$URL">$URL</a></td> </tr> </table> END_HTML # next row in result set $status = $resultSet->MoveNext; } use Data::Dumper; print Dumper(@save4later);

      Thanks a lot for your reply. You said in your comment that there are better ways of doing this without using while loop. I will highly appriciate if you can provide me better looping structure or solution where in I can retrive everything from ClearQuest and store it in a variable. Later I cau user that variable and all values for further processing.

        By following the principle of Separation of Concerns you would make your code more clear and easier to maintain. Beyond that, if this code is part of a larger project and you are displaying lots of HTML, then following CountZero's suggestion would be a good idea, but I'm not going to do that in this example.

        Just be aware of OOM issues since you would be storing all rows in memory up to 2x - once in CQ and once in perl - but at least 1x in perl depending on how CQ implements cursors.

        Also note that following SoC will sometimes make your code less efficient, like this case where we use multiple loops when we could have collapsed them such as in my first reply, but that's a judgement call for you to make on legibility & maintainability vs. efficiency.

        Btw, you should use strict; use warnings;. Hope this helps!

        $resultSet->Execute() or die "resultset error\n" ; my @all_rows ; push @all_rows, { Environment => $resultSet->GetColumnValue(1), Release => $resultSet->GetColumnValue(2), Project => $resultSet->GetColumnValue(3), VLS_Name => $resultSet->GetColumnValue(4), AppServerName => $resultSet->GetColumnValue(5), State => $resultSet->GetColumnValue(6), URL => $resultSet->GetColumnValue(7), } while ($resultSet->MoveNext() == $CQPerlExt::CQ_SUCCESS) ; print row2html($_) foreach (@all_rows) ; # debug # use Data::Dumper ; # print "debug:\n", Dumper($_), "\n" foreach (@all_rows) ; sub row2html { my $row = shift ; return " <table border='1' cellpadding='8' bgcolor='#CCD6F5'> <tr> <td><input type='checkbox' value='$row->{VLSName}'/></td> <td>$row->{Release}</td> <td>$row->{Environment}</td> <td width='160'>$row->{Project}</td> <td width='430'><a href='$row->{URL}'>$row->{URL}</a></td> </tr> </table> " ; }
Re: Capture output of a while loop into a variable
by CountZero (Bishop) on Sep 26, 2011 at 06:21 UTC
    I think this might be the right moment to start investing some time in learning about web-framworks like Catalyst or Dancer and templating with Template Toolkit or such.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James