[LON-CAPA-dev] Extracting problems from page or sequence

Jeremy Bowers lon-capa-dev@mail.lon-capa.org
Fri, 07 Feb 2003 16:41:37 -0500


H. K. Ng wrote:
> If you have a module that shows how to extract the problems from a page 
> or sequence, please let me know. I like to do the manual grading per 
> page/sequence for a given student.
> 
> Thanks,
> HK

One of the side effects of the recent changes to the nav maps is a 
(hopefully) nice interface to that sort of thing.

I'd start with "perldoc lonnavmaps.pm" (I don't think it's installed 
into the man pages, which I should probably fix), and let me know if you 
have any questions.

The basic routine goes like this:

1. Get a nav map object, which usually looks like this:

     my $navmap = Apache::lonnavmaps::navmap->new(
                         $ENV{"request.course.fn"}.".db",
                         $ENV{"request.course.fn"}."_parms.db", 1, 1);

    because the %ENV has that stuff for the current course already.

2. Somehow, figure out the Resource ID of the map you're interested in.

3. Get the resource object for that map:

     my $mapId = "6.1"; # or whatever
     my $map = $navmap->getById($mapId);

4. The $map has two methods of interest, map_start and map_finish, which
    are the first and last resources in the map. Now you want to
    construct an iterator, telling it to start and stop on those
    resources:

     my $iterator = $navmap->getIterator($map->map_start(),
         $map->map_finish())

5. Now you can query the iterator for the resources, in order. The while
    loop typically looks like this, as you can see in various places in
    the navmaps:

     my $depth = 1;
     $iterator->next(); # skip the first BEGIN_MAP
     my $curRes = $iterator->next(); # for "current resource"

     while ($depth > 0) {
         if($curRes == $iterator->BEGIN_MAP) { $depth++; }
         if($curRes == $iterator->END_MAP) { $depth++; }

         if(ref($curRes)) {
             # your code here, where $curRes is a resource object as
             # documented in lonnavmaps; there's a whole lotta stuff it
             # does
         }

         $curRes = $iterator->next(); # don't forget this or you
                                      # infinitely loop
     }



This will present each resource in order inside of the if(ref($curRes)) 
area. As I've shown here, it will *not* descend into any maps that may 
be contained in the map you are investigating. To change that, make the 
iterator call

     my $iterator = $navmap->getIterator($map->map_start(),
         $map->map_finish(), undef, 1);

which will recurse into all maps under the current one. (In that case 
you'll want to keep track of the depth.)

All the code lined up in a row:

     my $navmap = Apache::lonnavmaps::navmap->new(
                         $ENV{"request.course.fn"}.".db",
                         $ENV{"request.course.fn"}."_parms.db", 1, 1);

     my $mapId = "6.1"; # or whatever
     my $map = $navmap->getById($mapId);

     my $iterator = $navmap->getIterator($map->map_start(),
         $map->map_finish())

     # or
     # my $iterator = $navmap->getIterator($map->map_start(),
     #     $map->map_finish(), undef, 1);

     my $depth = 1;
     $iterator->next(); # skip the first BEGIN_MAP
     my $curRes = $iterator->next(); # for "current resource"

     while ($depth > 0) {
         if($curRes == $iterator->BEGIN_MAP) { $depth++; }
         if($curRes == $iterator->END_MAP) { $depth++; }

         if(ref($curRes)) {
             # your code here, where $curRes is a resource object as
             # documented in lonnavmaps; there's a whole lotta stuff it
             # does
         }

         $curRes = $iterator->next(); # don't forget this or you
                                      # infinitely loop
     }


More information about how to control how this works (such as 
selectively recursing into certain maps) is available on the lonnavmaps 
page. Please let me know if you have any problems; if the documentation 
is incomprehensible or inaccurate on some point, that's a bug.

If your sequence may contain things other then problems, you can use 
$curRes->is_problem() to check whether something is a problem.

(One of the things I'm working on right now is a filtering ability, so 
you can ask the iterator for just problems directly, because I need it 
elsewhere, but it isn't written quite yet so it certainly won't be 
available until the next release at the soonest. ;-) )