Multi-level list generation

Discussion in 'Perl Misc' started by Steve, Aug 21, 2010.

  1. Steve

    Steve Guest

    On 08/21/2010 02:04 PM, Tuxedo wrote:
    > I have a question about how to generate a multi-level (nested) list
    > structure by perl. I currently have a 2-level
    > <ul><li><ul><li></li></ul></li></ul> structure produced via a perl script,
    > which works fine for its purpose. An example HTML output by the existing
    > script is:
    >
    > <ul>
    > <li><a href=subject_1.0.html>Subject 1.0</a>
    > <ul>
    > <li><a href=page_1.1.html>Page 1.1</a></li>
    > <li><a href=page_1.2.html>Page 1.2</a></li>
    > <li><a href=page_1.3.html>Page 1.3</a></li>
    > </ul>
    > </li>
    > </ul>
    >
    > There's more non-relevant code that I've stripped for a bit of clarity,
    > such as CSS etc. In fact, the actual HTML code is largely irrelavant.
    > Anyway, a barebone version of the perl procedure generating the above is:
    >
    > #!/usr/bin/perl -w
    >
    > use Tie::IxHash;
    > use strict;
    > use warnings;
    >
    > my $object1 = tie my %listoflinks, "Tie::IxHash";
    >
    > %listoflinks = ('subject_1.0.html', => 'Subject 1.0',
    > 'page1.1.html', => 'Page 1.1',
    > 'page1.2.html', => 'Page 1.2',
    > 'page1.3.html', => 'Page 1.3');
    >
    > for (\%listoflinks) {
    > my $firstkey = each %$_;
    >
    > print "<ul>\n"; # open 1st UL
    >
    > print "<li><a href=$firstkey>$listoflinks{$firstkey}</a>\n"; # open 1st LI
    >
    > print "<ul>\n"; # open nested UL
    >
    > while ( local $_ = each %$_ ) {
    > { print "<li><a href=$_>$listoflinks{$_}</a></li> \n" } # print some LI's
    > }
    >
    > print "</ul>\n"; # close nested UL
    > print "</li>\n"; # close first LI
    > print "</ul>\n"; # close first UL
    >
    > }
    >
    > The above procedure was put together with good help from this group ages
    > ago. As mentioned, the code takes care of the 2-level list structure and
    > does so by fetching the $firstkey from the array entries or LoH and
    > inserting the needed opening and closing UL's and LI's in the right places.
    >
    > However, I'm not quite sure how to change the script to generate a third
    > level, such as:
    >
    > <ul>
    > <li><a href=subject_1.0.html>Subject 1.0</a>
    > <ul>
    > <li><a href=page_1.1.html>Page 1.1</a></li>
    > <li><a href=page_1.2.html>Page 1.2</a></li>
    > <li><a href=page_1.3.html>Page 1.3</a></li>
    > <li><a href=subject_2.0.html>Subject 2.0</a>
    > <ul>
    > <li><a href=page_2.1.html>Page 2.1</a></li>
    > <li><a href=page_2.1.html>Page 2.2</a></li>
    > </ul>
    > </li>
    > </ul>
    > </li>
    > </ul>
    >
    > Or for example, the same structure, with another two second-level list
    > items at the end:
    >
    > <ul>
    > <li><a href=subject_1.0.html>Subject 1.0</a>
    > <ul>
    > <li><a href=page_1.1.html>Page 1.1</a></li>
    > <li><a href=page_1.2.html>Page 1.2</a></li>
    > <li><a href=page_1.3.html>Page 1.3</a></li>
    > <li><a href=subject_2.0.html>Subject 2.0</a>
    > <ul>
    > <li><a href=page_2.1.html>Page 2.1</a></li>
    > <li><a href=page_2.1.html>Page 2.2</a></li>
    > </ul>
    > </li>
    > <li><a href=page_1.4.html>Page 1.4</a></li>
    > <li><a href=page_1.5.html>Page 1.5</a></li>
    > </ul>
    > </li>
    > </ul>
    >
    > Naturally a different array structure would be required in my %listoflinks
    > to output the above. Any advise or examples how this may be pieced together
    > would be most helpful.
    >
    > Perhaps someone has a procedure in use that does something similar already?
    >
    > Many thanks,
    > Tuxedo
    >
    > NB: System load efficiency is not an issue, as the procedure will run only
    > occasionally on a local machine to generate HTML sent onto a web server in
    > static format. In other words, the script will not run against any real web
    > page requests. The procedure is simply meant to be an easy maintenance tool.
    >
    >


    I use recursive routines a *lot* in printing out nested data structures,
    and they are your friend in cases like this...

    The below is:
    1) not tested in any way,
    2) may not even compile,
    3) and is just a concept.

    %hash = ( whatever, too lazy to make one );

    recurse_hash( \%hash );

    sub recurse_hash {
    my $refhash = shift;
    $refhash or return '';

    print "<ul>\n";

    while( keys %{$refhash} ){
    if( ref $refhash->{$_} eq 'HASH' ){
    recurse_hash( $refhash->{$_} );
    }
    else{
    print "<li>$refhash->{$_}</li>\n";
    }
    }

    print "</ul>\n";
    }

    The beauty of a recursive is it flat doesn't matter how many levels deep
    the data structure is.

    The downside is it flat doesn't matter how many levels deep the
    recursive 'thinks' the data structure is and sloppy programming can
    bite you big time..... infinite recursion anyone?

    hth,

    \s
    Steve, Aug 21, 2010
    #1
    1. Advertising

  2. Steve

    Tuxedo Guest

    I have a question about how to generate a multi-level (nested) list
    structure by perl. I currently have a 2-level
    <ul><li><ul><li></li></ul></li></ul> structure produced via a perl script,
    which works fine for its purpose. An example HTML output by the existing
    script is:

    <ul>
    <li><a href=subject_1.0.html>Subject 1.0</a>
    <ul>
    <li><a href=page_1.1.html>Page 1.1</a></li>
    <li><a href=page_1.2.html>Page 1.2</a></li>
    <li><a href=page_1.3.html>Page 1.3</a></li>
    </ul>
    </li>
    </ul>

    There's more non-relevant code that I've stripped for a bit of clarity,
    such as CSS etc. In fact, the actual HTML code is largely irrelavant.
    Anyway, a barebone version of the perl procedure generating the above is:

    #!/usr/bin/perl -w

    use Tie::IxHash;
    use strict;
    use warnings;

    my $object1 = tie my %listoflinks, "Tie::IxHash";

    %listoflinks = ('subject_1.0.html', => 'Subject 1.0',
    'page1.1.html', => 'Page 1.1',
    'page1.2.html', => 'Page 1.2',
    'page1.3.html', => 'Page 1.3');

    for (\%listoflinks) {
    my $firstkey = each %$_;

    print "<ul>\n"; # open 1st UL

    print "<li><a href=$firstkey>$listoflinks{$firstkey}</a>\n"; # open 1st LI

    print "<ul>\n"; # open nested UL

    while ( local $_ = each %$_ ) {
    { print "<li><a href=$_>$listoflinks{$_}</a></li> \n" } # print some LI's
    }

    print "</ul>\n"; # close nested UL
    print "</li>\n"; # close first LI
    print "</ul>\n"; # close first UL

    }

    The above procedure was put together with good help from this group ages
    ago. As mentioned, the code takes care of the 2-level list structure and
    does so by fetching the $firstkey from the array entries or LoH and
    inserting the needed opening and closing UL's and LI's in the right places.

    However, I'm not quite sure how to change the script to generate a third
    level, such as:

    <ul>
    <li><a href=subject_1.0.html>Subject 1.0</a>
    <ul>
    <li><a href=page_1.1.html>Page 1.1</a></li>
    <li><a href=page_1.2.html>Page 1.2</a></li>
    <li><a href=page_1.3.html>Page 1.3</a></li>
    <li><a href=subject_2.0.html>Subject 2.0</a>
    <ul>
    <li><a href=page_2.1.html>Page 2.1</a></li>
    <li><a href=page_2.1.html>Page 2.2</a></li>
    </ul>
    </li>
    </ul>
    </li>
    </ul>

    Or for example, the same structure, with another two second-level list
    items at the end:

    <ul>
    <li><a href=subject_1.0.html>Subject 1.0</a>
    <ul>
    <li><a href=page_1.1.html>Page 1.1</a></li>
    <li><a href=page_1.2.html>Page 1.2</a></li>
    <li><a href=page_1.3.html>Page 1.3</a></li>
    <li><a href=subject_2.0.html>Subject 2.0</a>
    <ul>
    <li><a href=page_2.1.html>Page 2.1</a></li>
    <li><a href=page_2.1.html>Page 2.2</a></li>
    </ul>
    </li>
    <li><a href=page_1.4.html>Page 1.4</a></li>
    <li><a href=page_1.5.html>Page 1.5</a></li>
    </ul>
    </li>
    </ul>

    Naturally a different array structure would be required in my %listoflinks
    to output the above. Any advise or examples how this may be pieced together
    would be most helpful.

    Perhaps someone has a procedure in use that does something similar already?

    Many thanks,
    Tuxedo

    NB: System load efficiency is not an issue, as the procedure will run only
    occasionally on a local machine to generate HTML sent onto a web server in
    static format. In other words, the script will not run against any real web
    page requests. The procedure is simply meant to be an easy maintenance tool.
    Tuxedo, Aug 21, 2010
    #2
    1. Advertising

  3. Steve

    Steve Guest

    On 08/21/2010 03:32 PM, Tuxedo wrote:
    > Steve wrote:
    >
    >> On 08/21/2010 02:04 PM, Tuxedo wrote:
    >>> I have a question about how to generate a multi-level (nested) list
    >>> structure by perl. I currently have a 2-level
    >>> <ul><li><ul><li></li></ul></li></ul> structure produced via a perl
    >>> script, which works fine for its purpose. An example HTML output by the
    >>> existing script is:
    >>>
    >>> <ul>
    >>> <li><a href=subject_1.0.html>Subject 1.0</a>
    >>> <ul>
    >>> <li><a href=page_1.1.html>Page 1.1</a></li>
    >>> <li><a href=page_1.2.html>Page 1.2</a></li>
    >>> <li><a href=page_1.3.html>Page 1.3</a></li>
    >>> </ul>
    >>> </li>
    >>> </ul>
    >>>
    >>> There's more non-relevant code that I've stripped for a bit of clarity,
    >>> such as CSS etc. In fact, the actual HTML code is largely irrelavant.
    >>> Anyway, a barebone version of the perl procedure generating the above
    >>> is:
    >>>
    >>> #!/usr/bin/perl -w
    >>>
    >>> use Tie::IxHash;
    >>> use strict;
    >>> use warnings;
    >>>
    >>> my $object1 = tie my %listoflinks, "Tie::IxHash";
    >>>
    >>> %listoflinks = ('subject_1.0.html', => 'Subject 1.0',
    >>> 'page1.1.html', => 'Page 1.1',
    >>> 'page1.2.html', => 'Page 1.2',
    >>> 'page1.3.html', => 'Page 1.3');
    >>>
    >>> for (\%listoflinks) {
    >>> my $firstkey = each %$_;
    >>>
    >>> print "<ul>\n"; # open 1st UL
    >>>
    >>> print "<li><a href=$firstkey>$listoflinks{$firstkey}</a>\n"; # open 1st
    >>> LI
    >>>
    >>> print "<ul>\n"; # open nested UL
    >>>
    >>> while ( local $_ = each %$_ ) {
    >>> { print "<li><a href=$_>$listoflinks{$_}</a></li> \n" } # print
    >>> some LI's }
    >>>
    >>> print "</ul>\n"; # close nested UL
    >>> print "</li>\n"; # close first LI
    >>> print "</ul>\n"; # close first UL
    >>>
    >>> }
    >>>
    >>> The above procedure was put together with good help from this group ages
    >>> ago. As mentioned, the code takes care of the 2-level list structure and
    >>> does so by fetching the $firstkey from the array entries or LoH and
    >>> inserting the needed opening and closing UL's and LI's in the right
    >>> places.
    >>>
    >>> However, I'm not quite sure how to change the script to generate a third
    >>> level, such as:
    >>>
    >>> <ul>
    >>> <li><a href=subject_1.0.html>Subject 1.0</a>
    >>> <ul>
    >>> <li><a href=page_1.1.html>Page 1.1</a></li>
    >>> <li><a href=page_1.2.html>Page 1.2</a></li>
    >>> <li><a href=page_1.3.html>Page 1.3</a></li>
    >>> <li><a href=subject_2.0.html>Subject 2.0</a>
    >>> <ul>
    >>> <li><a href=page_2.1.html>Page 2.1</a></li>
    >>> <li><a href=page_2.1.html>Page 2.2</a></li>
    >>> </ul>
    >>> </li>
    >>> </ul>
    >>> </li>
    >>> </ul>
    >>>
    >>> Or for example, the same structure, with another two second-level list
    >>> items at the end:
    >>>
    >>> <ul>
    >>> <li><a href=subject_1.0.html>Subject 1.0</a>
    >>> <ul>
    >>> <li><a href=page_1.1.html>Page 1.1</a></li>
    >>> <li><a href=page_1.2.html>Page 1.2</a></li>
    >>> <li><a href=page_1.3.html>Page 1.3</a></li>
    >>> <li><a href=subject_2.0.html>Subject 2.0</a>
    >>> <ul>
    >>> <li><a href=page_2.1.html>Page 2.1</a></li>
    >>> <li><a href=page_2.1.html>Page 2.2</a></li>
    >>> </ul>
    >>> </li>
    >>> <li><a href=page_1.4.html>Page 1.4</a></li>
    >>> <li><a href=page_1.5.html>Page 1.5</a></li>
    >>> </ul>
    >>> </li>
    >>> </ul>
    >>>
    >>> Naturally a different array structure would be required in my
    >>> %listoflinks to output the above. Any advise or examples how this may be
    >>> pieced together would be most helpful.
    >>>
    >>> Perhaps someone has a procedure in use that does something similar
    >>> already?
    >>>
    >>> Many thanks,
    >>> Tuxedo
    >>>
    >>> NB: System load efficiency is not an issue, as the procedure will run
    >>> only occasionally on a local machine to generate HTML sent onto a web
    >>> server in static format. In other words, the script will not run against
    >>> any real web page requests. The procedure is simply meant to be an easy
    >>> maintenance tool.
    >>>
    >>>

    >>
    >> I use recursive routines a *lot* in printing out nested data structures,
    >> and they are your friend in cases like this...
    >>
    >> The below is:
    >> 1) not tested in any way,
    >> 2) may not even compile,
    >> 3) and is just a concept.
    >>
    >> %hash = ( whatever, too lazy to make one );
    >>
    >> recurse_hash( \%hash );
    >>
    >> sub recurse_hash {
    >> my $refhash = shift;
    >> $refhash or return '';
    >>
    >> print "<ul>\n";
    >>
    >> while( keys %{$refhash} ){
    >> if( ref $refhash->{$_} eq 'HASH' ){
    >> recurse_hash( $refhash->{$_} );
    >> }
    >> else{
    >> print "<li>$refhash->{$_}</li>\n";
    >> }
    >> }
    >>
    >> print "</ul>\n";
    >> }
    >>
    >> The beauty of a recursive is it flat doesn't matter how many levels deep
    >> the data structure is.
    >>
    >> The downside is it flat doesn't matter how many levels deep the
    >> recursive 'thinks' the data structure is and sloppy programming can
    >> bite you big time..... infinite recursion anyone?
    >>
    >> hth,
    >>
    >> \s
    >>
    >>

    >
    > Thanks for the above solution! However, it is a bit difficult for me to
    > figure exactly how the %hash = (part may be composed) to generate a
    > multi-level list structure. Any additional pointers anyone?
    >
    > Tuxedo
    >
    >
    >


    Well.....

    my %hash = (
    key1 => { subkey => 'value',
    subhash => {
    subsubkey1 => 'value',
    subsubkey2 => 'another value',
    },
    },
    key2 => 'value',
    etc => {
    },

    );

    But, 'more better' would be to go a reliable (and vetted) source like:

    http://perldoc.perl.org/perldsc.html

    hth,

    \s
    Steve, Aug 21, 2010
    #3
  4. Tuxedo <> wrote:
    >I have a question about how to generate a multi-level (nested) list
    >structure by perl. I currently have a 2-level
    ><ul><li><ul><li></li></ul></li></ul> structure produced via a perl script,
    >which works fine for its purpose. An example HTML output by the existing
    >script is:

    [...]

    >The above procedure was put together with good help from this group ages
    >ago. As mentioned, the code takes care of the 2-level list structure and
    >does so by fetching the $firstkey from the array entries or LoH and
    >inserting the needed opening and closing UL's and LI's in the right places.
    >
    >However, I'm not quite sure how to change the script to generate a third
    >level, such as:


    If you keep adding additional levels then recursion is your friend:
    (sketch in pseudo-code, transfer into actual Perl is left as an
    excercise):

    sub print_elem {
    #arguments: single argument, either reference to list or single item
    if (ref $_[0]) { # this element is a reference to a nested list
    print_header(); #print header for the sub-list
    for (@_) {
    print_elem(@{$_}); #print each element of the sub-list
    }
    print_footer(); #print footer for the sub-list

    } else { #this element is a single item
    print_item($_[0]; #just print it
    }
    )


    jue
    Jürgen Exner, Aug 21, 2010
    #4
  5. Steve

    Tuxedo Guest

    Steve wrote:

    > On 08/21/2010 02:04 PM, Tuxedo wrote:
    > > I have a question about how to generate a multi-level (nested) list
    > > structure by perl. I currently have a 2-level
    > > <ul><li><ul><li></li></ul></li></ul> structure produced via a perl
    > > script, which works fine for its purpose. An example HTML output by the
    > > existing script is:
    > >
    > > <ul>
    > > <li><a href=subject_1.0.html>Subject 1.0</a>
    > > <ul>
    > > <li><a href=page_1.1.html>Page 1.1</a></li>
    > > <li><a href=page_1.2.html>Page 1.2</a></li>
    > > <li><a href=page_1.3.html>Page 1.3</a></li>
    > > </ul>
    > > </li>
    > > </ul>
    > >
    > > There's more non-relevant code that I've stripped for a bit of clarity,
    > > such as CSS etc. In fact, the actual HTML code is largely irrelavant.
    > > Anyway, a barebone version of the perl procedure generating the above
    > > is:
    > >
    > > #!/usr/bin/perl -w
    > >
    > > use Tie::IxHash;
    > > use strict;
    > > use warnings;
    > >
    > > my $object1 = tie my %listoflinks, "Tie::IxHash";
    > >
    > > %listoflinks = ('subject_1.0.html', => 'Subject 1.0',
    > > 'page1.1.html', => 'Page 1.1',
    > > 'page1.2.html', => 'Page 1.2',
    > > 'page1.3.html', => 'Page 1.3');
    > >
    > > for (\%listoflinks) {
    > > my $firstkey = each %$_;
    > >
    > > print "<ul>\n"; # open 1st UL
    > >
    > > print "<li><a href=$firstkey>$listoflinks{$firstkey}</a>\n"; # open 1st
    > > LI
    > >
    > > print "<ul>\n"; # open nested UL
    > >
    > > while ( local $_ = each %$_ ) {
    > > { print "<li><a href=$_>$listoflinks{$_}</a></li> \n" } # print
    > > some LI's }
    > >
    > > print "</ul>\n"; # close nested UL
    > > print "</li>\n"; # close first LI
    > > print "</ul>\n"; # close first UL
    > >
    > > }
    > >
    > > The above procedure was put together with good help from this group ages
    > > ago. As mentioned, the code takes care of the 2-level list structure and
    > > does so by fetching the $firstkey from the array entries or LoH and
    > > inserting the needed opening and closing UL's and LI's in the right
    > > places.
    > >
    > > However, I'm not quite sure how to change the script to generate a third
    > > level, such as:
    > >
    > > <ul>
    > > <li><a href=subject_1.0.html>Subject 1.0</a>
    > > <ul>
    > > <li><a href=page_1.1.html>Page 1.1</a></li>
    > > <li><a href=page_1.2.html>Page 1.2</a></li>
    > > <li><a href=page_1.3.html>Page 1.3</a></li>
    > > <li><a href=subject_2.0.html>Subject 2.0</a>
    > > <ul>
    > > <li><a href=page_2.1.html>Page 2.1</a></li>
    > > <li><a href=page_2.1.html>Page 2.2</a></li>
    > > </ul>
    > > </li>
    > > </ul>
    > > </li>
    > > </ul>
    > >
    > > Or for example, the same structure, with another two second-level list
    > > items at the end:
    > >
    > > <ul>
    > > <li><a href=subject_1.0.html>Subject 1.0</a>
    > > <ul>
    > > <li><a href=page_1.1.html>Page 1.1</a></li>
    > > <li><a href=page_1.2.html>Page 1.2</a></li>
    > > <li><a href=page_1.3.html>Page 1.3</a></li>
    > > <li><a href=subject_2.0.html>Subject 2.0</a>
    > > <ul>
    > > <li><a href=page_2.1.html>Page 2.1</a></li>
    > > <li><a href=page_2.1.html>Page 2.2</a></li>
    > > </ul>
    > > </li>
    > > <li><a href=page_1.4.html>Page 1.4</a></li>
    > > <li><a href=page_1.5.html>Page 1.5</a></li>
    > > </ul>
    > > </li>
    > > </ul>
    > >
    > > Naturally a different array structure would be required in my
    > > %listoflinks to output the above. Any advise or examples how this may be
    > > pieced together would be most helpful.
    > >
    > > Perhaps someone has a procedure in use that does something similar
    > > already?
    > >
    > > Many thanks,
    > > Tuxedo
    > >
    > > NB: System load efficiency is not an issue, as the procedure will run
    > > only occasionally on a local machine to generate HTML sent onto a web
    > > server in static format. In other words, the script will not run against
    > > any real web page requests. The procedure is simply meant to be an easy
    > > maintenance tool.
    > >
    > >

    >
    > I use recursive routines a *lot* in printing out nested data structures,
    > and they are your friend in cases like this...
    >
    > The below is:
    > 1) not tested in any way,
    > 2) may not even compile,
    > 3) and is just a concept.
    >
    > %hash = ( whatever, too lazy to make one );
    >
    > recurse_hash( \%hash );
    >
    > sub recurse_hash {
    > my $refhash = shift;
    > $refhash or return '';
    >
    > print "<ul>\n";
    >
    > while( keys %{$refhash} ){
    > if( ref $refhash->{$_} eq 'HASH' ){
    > recurse_hash( $refhash->{$_} );
    > }
    > else{
    > print "<li>$refhash->{$_}</li>\n";
    > }
    > }
    >
    > print "</ul>\n";
    > }
    >
    > The beauty of a recursive is it flat doesn't matter how many levels deep
    > the data structure is.
    >
    > The downside is it flat doesn't matter how many levels deep the
    > recursive 'thinks' the data structure is and sloppy programming can
    > bite you big time..... infinite recursion anyone?
    >
    > hth,
    >
    > \s
    >
    >


    Thanks for the above solution! However, it is a bit difficult for me to
    figure exactly how the %hash = (part may be composed) to generate a
    multi-level list structure. Any additional pointers anyone?

    Tuxedo
    Tuxedo, Aug 21, 2010
    #5
  6. Steve

    Tuxedo Guest

    Jürgen Exner wrote:

    > Tuxedo <> wrote:
    > >I have a question about how to generate a multi-level (nested) list
    > >structure by perl. I currently have a 2-level
    > ><ul><li><ul><li></li></ul></li></ul> structure produced via a perl
    > >script, which works fine for its purpose. An example HTML output by the
    > >existing script is:

    > [...]
    >
    > >The above procedure was put together with good help from this group ages
    > >ago. As mentioned, the code takes care of the 2-level list structure and
    > >does so by fetching the $firstkey from the array entries or LoH and
    > >inserting the needed opening and closing UL's and LI's in the right
    > >places.
    > >
    > >However, I'm not quite sure how to change the script to generate a third
    > >level, such as:

    >
    > If you keep adding additional levels then recursion is your friend:
    > (sketch in pseudo-code, transfer into actual Perl is left as an
    > excercise):
    >
    > sub print_elem {
    > #arguments: single argument, either reference to list or single item
    > if (ref $_[0]) { # this element is a reference to a nested list
    > print_header(); #print header for the sub-list
    > for (@_) {
    > print_elem(@{$_}); #print each element of the sub-list
    > }
    > print_footer(); #print footer for the sub-list
    >
    > } else { #this element is a single item
    > print_item($_[0]; #just print it
    > }
    > )
    >
    >
    > jue


    This looks like a good solution. Yet difficult for me to translate into
    functioning code against an array of hash values or items.

    Any bit of clearer description would be greatly appreciated.

    Thanks,
    Tuxedo
    Tuxedo, Aug 21, 2010
    #6
  7. Steve

    ccc31807 Guest

    On Aug 21, 3:04 pm, Tuxedo <> wrote:
    > I have a question about how to generate a multi-level (nested) list
    > structure by perl. I currently have a 2-level
    > <ul><li><ul><li></li></ul></li></ul> structure produced via a perl script,
    > which works fine for its purpose. An example HTML output by the existing
    > script is:


    Mark Jason Dominus, in 'Higher Order Perl' has a section on parsing
    HTML in chapter 1. You can download the book over the internet, but
    it's well worth buying, and I would encourage you to do so.

    CC
    ccc31807, Aug 22, 2010
    #7
  8. Steve

    Uri Guttman Guest

    >>>>> "c" == ccc31807 <> writes:

    c> On Aug 21, 3:04 pm, Tuxedo <> wrote:
    >> I have a question about how to generate a multi-level (nested) list
    >> structure by perl. I currently have a 2-level
    >> <ul><li><ul><li></li></ul></li></ul> structure produced via a perl script,
    >> which works fine for its purpose. An example HTML output by the existing
    >> script is:


    c> Mark Jason Dominus, in 'Higher Order Perl' has a section on parsing
    c> HTML in chapter 1. You can download the book over the internet, but
    c> it's well worth buying, and I would encourage you to do so.

    the OP isn't parsing but generating html. parsing it should be done with
    a module. generating it is done well with templates but he still needs
    to learn data structures to work with them. regardless of the
    technology, nested html needs nested data which means perl data
    structures. they are used in some many perl programs that they are
    critical to learn early one. perlreftut, perldsc and perllol are
    required reading from the perl docs.

    uri

    --
    Uri Guttman ------ -------- http://www.sysarch.com --
    ----- Perl Code Review , Architecture, Development, Training, Support ------
    --------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
    Uri Guttman, Aug 22, 2010
    #8
  9. Steve

    Tuxedo Guest

    Steve wrote:

    > On 08/21/2010 03:32 PM, Tuxedo wrote:
    > > Steve wrote:
    > >
    > >> On 08/21/2010 02:04 PM, Tuxedo wrote:
    > >>> I have a question about how to generate a multi-level (nested) list
    > >>> structure by perl. I currently have a 2-level
    > >>> <ul><li><ul><li></li></ul></li></ul> structure produced via a perl
    > >>> script, which works fine for its purpose. An example HTML output by
    > >>> the existing script is:
    > >>>
    > >>> <ul>
    > >>> <li><a href=subject_1.0.html>Subject 1.0</a>
    > >>> <ul>
    > >>> <li><a href=page_1.1.html>Page 1.1</a></li>
    > >>> <li><a href=page_1.2.html>Page 1.2</a></li>
    > >>> <li><a href=page_1.3.html>Page 1.3</a></li>
    > >>> </ul>
    > >>> </li>
    > >>> </ul>
    > >>>
    > >>> There's more non-relevant code that I've stripped for a bit of
    > >>> clarity, such as CSS etc. In fact, the actual HTML code is largely
    > >>> irrelavant. Anyway, a barebone version of the perl procedure
    > >>> generating the above is:
    > >>>
    > >>> #!/usr/bin/perl -w
    > >>>
    > >>> use Tie::IxHash;
    > >>> use strict;
    > >>> use warnings;
    > >>>
    > >>> my $object1 = tie my %listoflinks, "Tie::IxHash";
    > >>>
    > >>> %listoflinks = ('subject_1.0.html', => 'Subject 1.0',
    > >>> 'page1.1.html', => 'Page 1.1',
    > >>> 'page1.2.html', => 'Page 1.2',
    > >>> 'page1.3.html', => 'Page 1.3');
    > >>>
    > >>> for (\%listoflinks) {
    > >>> my $firstkey = each %$_;
    > >>>
    > >>> print "<ul>\n"; # open 1st UL
    > >>>
    > >>> print "<li><a href=$firstkey>$listoflinks{$firstkey}</a>\n"; # open
    > >>> 1st LI
    > >>>
    > >>> print "<ul>\n"; # open nested UL
    > >>>
    > >>> while ( local $_ = each %$_ ) {
    > >>> { print "<li><a href=$_>$listoflinks{$_}</a></li> \n" } # print
    > >>> some LI's }
    > >>>
    > >>> print "</ul>\n"; # close nested UL
    > >>> print "</li>\n"; # close first LI
    > >>> print "</ul>\n"; # close first UL
    > >>>
    > >>> }
    > >>>
    > >>> The above procedure was put together with good help from this group
    > >>> ages ago. As mentioned, the code takes care of the 2-level list
    > >>> structure and does so by fetching the $firstkey from the array entries
    > >>> or LoH and inserting the needed opening and closing UL's and LI's in
    > >>> the right places.
    > >>>
    > >>> However, I'm not quite sure how to change the script to generate a
    > >>> third level, such as:
    > >>>
    > >>> <ul>
    > >>> <li><a href=subject_1.0.html>Subject 1.0</a>
    > >>> <ul>
    > >>> <li><a href=page_1.1.html>Page 1.1</a></li>
    > >>> <li><a href=page_1.2.html>Page 1.2</a></li>
    > >>> <li><a href=page_1.3.html>Page 1.3</a></li>
    > >>> <li><a href=subject_2.0.html>Subject 2.0</a>
    > >>> <ul>
    > >>> <li><a href=page_2.1.html>Page 2.1</a></li>
    > >>> <li><a href=page_2.1.html>Page 2.2</a></li>
    > >>> </ul>
    > >>> </li>
    > >>> </ul>
    > >>> </li>
    > >>> </ul>
    > >>>
    > >>> Or for example, the same structure, with another two second-level list
    > >>> items at the end:
    > >>>
    > >>> <ul>
    > >>> <li><a href=subject_1.0.html>Subject 1.0</a>
    > >>> <ul>
    > >>> <li><a href=page_1.1.html>Page 1.1</a></li>
    > >>> <li><a href=page_1.2.html>Page 1.2</a></li>
    > >>> <li><a href=page_1.3.html>Page 1.3</a></li>
    > >>> <li><a href=subject_2.0.html>Subject 2.0</a>
    > >>> <ul>
    > >>> <li><a href=page_2.1.html>Page 2.1</a></li>
    > >>> <li><a href=page_2.1.html>Page 2.2</a></li>
    > >>> </ul>
    > >>> </li>
    > >>> <li><a href=page_1.4.html>Page 1.4</a></li>
    > >>> <li><a href=page_1.5.html>Page 1.5</a></li>
    > >>> </ul>
    > >>> </li>
    > >>> </ul>
    > >>>
    > >>> Naturally a different array structure would be required in my
    > >>> %listoflinks to output the above. Any advise or examples how this may
    > >>> be pieced together would be most helpful.
    > >>>
    > >>> Perhaps someone has a procedure in use that does something similar
    > >>> already?
    > >>>
    > >>> Many thanks,
    > >>> Tuxedo
    > >>>
    > >>> NB: System load efficiency is not an issue, as the procedure will run
    > >>> only occasionally on a local machine to generate HTML sent onto a web
    > >>> server in static format. In other words, the script will not run
    > >>> against any real web page requests. The procedure is simply meant to
    > >>> be an easy maintenance tool.
    > >>>
    > >>>
    > >>
    > >> I use recursive routines a *lot* in printing out nested data
    > >> structures, and they are your friend in cases like this...
    > >>
    > >> The below is:
    > >> 1) not tested in any way,
    > >> 2) may not even compile,
    > >> 3) and is just a concept.
    > >>
    > >> %hash = ( whatever, too lazy to make one );
    > >>
    > >> recurse_hash( \%hash );
    > >>
    > >> sub recurse_hash {
    > >> my $refhash = shift;
    > >> $refhash or return '';
    > >>
    > >> print "<ul>\n";
    > >>
    > >> while( keys %{$refhash} ){
    > >> if( ref $refhash->{$_} eq 'HASH' ){
    > >> recurse_hash( $refhash->{$_} );
    > >> }
    > >> else{
    > >> print "<li>$refhash->{$_}</li>\n";
    > >> }
    > >> }
    > >>
    > >> print "</ul>\n";
    > >> }
    > >>
    > >> The beauty of a recursive is it flat doesn't matter how many levels
    > >> deep the data structure is.
    > >>
    > >> The downside is it flat doesn't matter how many levels deep the
    > >> recursive 'thinks' the data structure is and sloppy programming can
    > >> bite you big time..... infinite recursion anyone?
    > >>
    > >> hth,
    > >>
    > >> \s
    > >>
    > >>

    > >
    > > Thanks for the above solution! However, it is a bit difficult for me to
    > > figure exactly how the %hash = (part may be composed) to generate a
    > > multi-level list structure. Any additional pointers anyone?
    > >
    > > Tuxedo
    > >
    > >
    > >

    >
    > Well.....
    >
    > my %hash = (
    > key1 => { subkey => 'value',
    > subhash => {
    > subsubkey1 => 'value',
    > subsubkey2 => 'another value',
    > },
    > },
    > key2 => 'value',
    > etc => {
    > },
    >
    > );
    >
    > But, 'more better' would be to go a reliable (and vetted) source like:
    >
    > http://perldoc.perl.org/perldsc.html
    >
    > hth,
    >
    > \s



    Thanks for the hash example and perldoc resource. However, it's still a bit
    confusing. To gain a bit further understanding I tried to run your script
    'as is' but it failed to compile, as of course you warned me it may do. In
    saving your script as a file named testrun.pl and running it, the following
    errors are repeatedly returned to the shell until I hit Ctrl+C:

    <li></li>
    Use of uninitialized value in hash element at ./testrun.pl line 27.
    Use of uninitialized value in hash element at ./testrun.pl line 31.
    Use of uninitialized value in concatenation (.) or string at ./testrun.pl
    line 31.
    <li></li>
    Use of uninitialized value in hash element at ./testrun.pl line 27.
    Use of uninitialized value in hash element at ./testrun.pl line 31.
    Use of uninitialized value in concatenation (.) or string at ./testrun.pl
    line 31.
    <li></li>

    etc.

    Unfortunately I do not understand the meaning of the above errors and if I
    redirect the output to a file, like in ./testrun.pl > file.txt, the file
    contains a long list of empty <li></li> containers after an opening <ul>:

    <ul>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>

    etc...

    Below is the exact copy of what I tried to run:

    #!/usr/bin/perl -w

    use strict;
    use warnings;

    my %hash = (
    key1 => { subkey => 'value',
    subhash => {
    subsubkey1 => 'value',
    subsubkey2 => 'another value',
    },
    },
    key2 => 'value',

    );


    recurse_hash( \%hash );

    sub recurse_hash {
    my $refhash = shift;
    $refhash or return '';

    print "<ul>\n";

    while( keys %{$refhash} ){
    if( ref $refhash->{$_} eq 'HASH' ){
    recurse_hash( $refhash->{$_} );
    }
    else{
    print "<li>$refhash->{$_}</li>\n";
    }
    }

    print "</ul>\n";
    }

    Anyone knows where the error(s) in the above procedure are?

    Thanks again,
    Tuxedo
    Tuxedo, Aug 22, 2010
    #9
  10. Steve

    Tuxedo Guest

    ccc31807 wrote:

    > On Aug 21, 3:04 pm, Tuxedo <> wrote:
    > > I have a question about how to generate a multi-level (nested) list
    > > structure by perl. I currently have a 2-level
    > > <ul><li><ul><li></li></ul></li></ul> structure produced via a perl
    > > script, which works fine for its purpose. An example HTML output by the
    > > existing script is:

    >
    > Mark Jason Dominus, in 'Higher Order Perl' has a section on parsing
    > HTML in chapter 1. You can download the book over the internet, but
    > it's well worth buying, and I would encourage you to do so.
    >
    > CC


    Thanks for the tip. Seems to be a good book!

    Tuxedo
    Tuxedo, Aug 22, 2010
    #10
  11. Steve

    Tuxedo Guest

    Uri Guttman wrote:

    > >>>>> "c" == ccc31807 <> writes:

    >
    > c> On Aug 21, 3:04 pm, Tuxedo <> wrote:
    > >> I have a question about how to generate a multi-level (nested) list
    > >> structure by perl. I currently have a 2-level
    > >> <ul><li><ul><li></li></ul></li></ul> structure produced via a perl
    > >> script, which works fine for its purpose. An example HTML output by
    > >> the existing script is:

    >
    > c> Mark Jason Dominus, in 'Higher Order Perl' has a section on parsing
    > c> HTML in chapter 1. You can download the book over the internet, but
    > c> it's well worth buying, and I would encourage you to do so.
    >
    > the OP isn't parsing but generating html. parsing it should be done with
    > a module. generating it is done well with templates but he still needs
    > to learn data structures to work with them. regardless of the
    > technology, nested html needs nested data which means perl data
    > structures. they are used in some many perl programs that they are
    > critical to learn early one. perlreftut, perldsc and perllol are
    > required reading from the perl docs.
    >
    > uri
    >


    Will look into perlreftut, perldsc and perllol. My task may seem trivial,
    but as you say, the relevant data structures are needed, which makes this
    one a hard nut to crack without a fairly deep level of perl knowledge.

    Tuxedo
    Tuxedo, Aug 22, 2010
    #11
  12. Steve

    Steve Guest

    On 08/22/2010 07:19 AM, Tuxedo wrote:
    > Steve wrote:
    >
    >> On 08/21/2010 03:32 PM, Tuxedo wrote:
    >>> Steve wrote:
    >>>
    >>>> On 08/21/2010 02:04 PM, Tuxedo wrote:
    >>>>> I have a question about how to generate a multi-level (nested) list
    >>>>> structure by perl. I currently have a 2-level
    >>>>> <ul><li><ul><li></li></ul></li></ul> structure produced via a perl
    >>>>> script, which works fine for its purpose. An example HTML output by
    >>>>> the existing script is:
    >>>>>
    >>>>> <ul>
    >>>>> <li><a href=subject_1.0.html>Subject 1.0</a>
    >>>>> <ul>
    >>>>> <li><a href=page_1.1.html>Page 1.1</a></li>
    >>>>> <li><a href=page_1.2.html>Page 1.2</a></li>
    >>>>> <li><a href=page_1.3.html>Page 1.3</a></li>
    >>>>> </ul>
    >>>>> </li>
    >>>>> </ul>
    >>>>>
    >>>>> There's more non-relevant code that I've stripped for a bit of
    >>>>> clarity, such as CSS etc. In fact, the actual HTML code is largely
    >>>>> irrelavant. Anyway, a barebone version of the perl procedure
    >>>>> generating the above is:
    >>>>>
    >>>>> #!/usr/bin/perl -w
    >>>>>
    >>>>> use Tie::IxHash;
    >>>>> use strict;
    >>>>> use warnings;
    >>>>>
    >>>>> my $object1 = tie my %listoflinks, "Tie::IxHash";
    >>>>>
    >>>>> %listoflinks = ('subject_1.0.html', => 'Subject 1.0',
    >>>>> 'page1.1.html', => 'Page 1.1',
    >>>>> 'page1.2.html', => 'Page 1.2',
    >>>>> 'page1.3.html', => 'Page 1.3');
    >>>>>
    >>>>> for (\%listoflinks) {
    >>>>> my $firstkey = each %$_;
    >>>>>
    >>>>> print "<ul>\n"; # open 1st UL
    >>>>>
    >>>>> print "<li><a href=$firstkey>$listoflinks{$firstkey}</a>\n"; # open
    >>>>> 1st LI
    >>>>>
    >>>>> print "<ul>\n"; # open nested UL
    >>>>>
    >>>>> while ( local $_ = each %$_ ) {
    >>>>> { print "<li><a href=$_>$listoflinks{$_}</a></li> \n" } # print
    >>>>> some LI's }
    >>>>>
    >>>>> print "</ul>\n"; # close nested UL
    >>>>> print "</li>\n"; # close first LI
    >>>>> print "</ul>\n"; # close first UL
    >>>>>
    >>>>> }
    >>>>>
    >>>>> The above procedure was put together with good help from this group
    >>>>> ages ago. As mentioned, the code takes care of the 2-level list
    >>>>> structure and does so by fetching the $firstkey from the array entries
    >>>>> or LoH and inserting the needed opening and closing UL's and LI's in
    >>>>> the right places.
    >>>>>
    >>>>> However, I'm not quite sure how to change the script to generate a
    >>>>> third level, such as:
    >>>>>
    >>>>> <ul>
    >>>>> <li><a href=subject_1.0.html>Subject 1.0</a>
    >>>>> <ul>
    >>>>> <li><a href=page_1.1.html>Page 1.1</a></li>
    >>>>> <li><a href=page_1.2.html>Page 1.2</a></li>
    >>>>> <li><a href=page_1.3.html>Page 1.3</a></li>
    >>>>> <li><a href=subject_2.0.html>Subject 2.0</a>
    >>>>> <ul>
    >>>>> <li><a href=page_2.1.html>Page 2.1</a></li>
    >>>>> <li><a href=page_2.1.html>Page 2.2</a></li>
    >>>>> </ul>
    >>>>> </li>
    >>>>> </ul>
    >>>>> </li>
    >>>>> </ul>
    >>>>>
    >>>>> Or for example, the same structure, with another two second-level list
    >>>>> items at the end:
    >>>>>
    >>>>> <ul>
    >>>>> <li><a href=subject_1.0.html>Subject 1.0</a>
    >>>>> <ul>
    >>>>> <li><a href=page_1.1.html>Page 1.1</a></li>
    >>>>> <li><a href=page_1.2.html>Page 1.2</a></li>
    >>>>> <li><a href=page_1.3.html>Page 1.3</a></li>
    >>>>> <li><a href=subject_2.0.html>Subject 2.0</a>
    >>>>> <ul>
    >>>>> <li><a href=page_2.1.html>Page 2.1</a></li>
    >>>>> <li><a href=page_2.1.html>Page 2.2</a></li>
    >>>>> </ul>
    >>>>> </li>
    >>>>> <li><a href=page_1.4.html>Page 1.4</a></li>
    >>>>> <li><a href=page_1.5.html>Page 1.5</a></li>
    >>>>> </ul>
    >>>>> </li>
    >>>>> </ul>
    >>>>>
    >>>>> Naturally a different array structure would be required in my
    >>>>> %listoflinks to output the above. Any advise or examples how this may
    >>>>> be pieced together would be most helpful.
    >>>>>
    >>>>> Perhaps someone has a procedure in use that does something similar
    >>>>> already?
    >>>>>
    >>>>> Many thanks,
    >>>>> Tuxedo
    >>>>>
    >>>>> NB: System load efficiency is not an issue, as the procedure will run
    >>>>> only occasionally on a local machine to generate HTML sent onto a web
    >>>>> server in static format. In other words, the script will not run
    >>>>> against any real web page requests. The procedure is simply meant to
    >>>>> be an easy maintenance tool.
    >>>>>
    >>>>>
    >>>>
    >>>> I use recursive routines a *lot* in printing out nested data
    >>>> structures, and they are your friend in cases like this...
    >>>>
    >>>> The below is:
    >>>> 1) not tested in any way,
    >>>> 2) may not even compile,
    >>>> 3) and is just a concept.
    >>>>
    >>>> %hash = ( whatever, too lazy to make one );
    >>>>
    >>>> recurse_hash( \%hash );
    >>>>
    >>>> sub recurse_hash {
    >>>> my $refhash = shift;
    >>>> $refhash or return '';
    >>>>
    >>>> print "<ul>\n";
    >>>>
    >>>> while( keys %{$refhash} ){
    >>>> if( ref $refhash->{$_} eq 'HASH' ){
    >>>> recurse_hash( $refhash->{$_} );
    >>>> }
    >>>> else{
    >>>> print "<li>$refhash->{$_}</li>\n";
    >>>> }
    >>>> }
    >>>>
    >>>> print "</ul>\n";
    >>>> }
    >>>>
    >>>> The beauty of a recursive is it flat doesn't matter how many levels
    >>>> deep the data structure is.
    >>>>
    >>>> The downside is it flat doesn't matter how many levels deep the
    >>>> recursive 'thinks' the data structure is and sloppy programming can
    >>>> bite you big time..... infinite recursion anyone?
    >>>>
    >>>> hth,
    >>>>
    >>>> \s
    >>>>
    >>>>
    >>>
    >>> Thanks for the above solution! However, it is a bit difficult for me to
    >>> figure exactly how the %hash = (part may be composed) to generate a
    >>> multi-level list structure. Any additional pointers anyone?
    >>>
    >>> Tuxedo
    >>>
    >>>
    >>>

    >>
    >> Well.....
    >>
    >> my %hash = (
    >> key1 => { subkey => 'value',
    >> subhash => {
    >> subsubkey1 => 'value',
    >> subsubkey2 => 'another value',
    >> },
    >> },
    >> key2 => 'value',
    >> etc => {
    >> },
    >>
    >> );
    >>
    >> But, 'more better' would be to go a reliable (and vetted) source like:
    >>
    >> http://perldoc.perl.org/perldsc.html
    >>
    >> hth,
    >>
    >> \s

    >
    >
    > Thanks for the hash example and perldoc resource. However, it's still a bit
    > confusing. To gain a bit further understanding I tried to run your script
    > 'as is' but it failed to compile, as of course you warned me it may do. In
    > saving your script as a file named testrun.pl and running it, the following
    > errors are repeatedly returned to the shell until I hit Ctrl+C:
    >
    > <li></li>
    > Use of uninitialized value in hash element at ./testrun.pl line 27.
    > Use of uninitialized value in hash element at ./testrun.pl line 31.
    > Use of uninitialized value in concatenation (.) or string at ./testrun.pl
    > line 31.
    > <li></li>
    > Use of uninitialized value in hash element at ./testrun.pl line 27.
    > Use of uninitialized value in hash element at ./testrun.pl line 31.
    > Use of uninitialized value in concatenation (.) or string at ./testrun.pl
    > line 31.
    > <li></li>
    >
    > etc.
    >
    > Unfortunately I do not understand the meaning of the above errors and if I
    > redirect the output to a file, like in ./testrun.pl> file.txt, the file
    > contains a long list of empty<li></li> containers after an opening<ul>:
    >
    > <ul>
    > <li></li>
    > <li></li>
    > <li></li>
    > <li></li>
    > <li></li>
    > <li></li>
    > <li></li>
    > <li></li>
    > <li></li>
    > <li></li>
    >
    > etc...
    >
    > Below is the exact copy of what I tried to run:
    >
    > #!/usr/bin/perl -w
    >
    > use strict;
    > use warnings;
    >
    > my %hash = (
    > key1 => { subkey => 'value',
    > subhash => {
    > subsubkey1 => 'value',
    > subsubkey2 => 'another value',
    > },
    > },
    > key2 => 'value',
    >
    > );
    >
    >
    > recurse_hash( \%hash );
    >
    > sub recurse_hash {
    > my $refhash = shift;
    > $refhash or return '';
    >
    > print "<ul>\n";
    >
    > while( keys %{$refhash} ){
    > if( ref $refhash->{$_} eq 'HASH' ){
    > recurse_hash( $refhash->{$_} );
    > }
    > else{
    > print "<li>$refhash->{$_}</li>\n";
    > }
    > }
    >
    > print "</ul>\n";
    > }
    >
    > Anyone knows where the error(s) in the above procedure are?
    >
    > Thanks again,
    > Tuxedo
    >
    >
    >


    OK, here:
    1) tested
    2) compiles
    3) works


    #! /usr/bin/perl

    use warnings;
    use strict;

    my %one = (
    onek1v1 => 'hash one value 1',
    onek2v1 => 'hash one value 2',
    );

    my %oneref = (
    onerefk1v1 => { anotherlevel => 'hash one down two' },
    onerefval => 'hash one value down one',
    );

    $one{'downone'} = \%oneref;

    my %two = (
    twok1v1 => 'hash two value 1',
    twok2v1 => 'hash two value 2',
    );

    my %three = (
    threek1v1 => 'hash three value 1',
    threek2v1 => 'hash three value 2',
    );

    my %main_hash = (
    one => \%one,
    two => \%two,
    three => \%three,
    );

    recurse_hash( \%main_hash );

    our $spct = 0; ## track leading spaces count

    sub recurse_hash {

    my $refhash = shift;
    $refhash or return '';

    $spct and print ' ' x $spct; # spacecount x spacespace

    print "<ul>\n";

    $spct += 1;

    for( keys %{$refhash} ){

    if( ref $refhash->{$_} eq 'HASH' ){

    $spct += 1;

    recurse_hash( $refhash->{$_} );

    $spct -= 1;
    }
    else{

    $spct+= 1;
    print ' ' x $spct;

    print "<li>$refhash->{$_}</li>\n";

    $spct -= 1;
    }
    }

    $spct -= 1;

    print ' ' x $spct;

    print "</ul>\n";

    }

    exit;


    Command line Output:

    <ul>
    <ul>
    <li>hash three value 1</li>
    <li>hash three value 2</li>
    </ul>
    <ul>
    <li>hash one value 2</li>
    <ul>
    <li>hash one value down one</li>
    <ul>
    <li>hash one down two</li>
    </ul>
    </ul>
    <li>hash one value 1</li>
    </ul>
    <ul>
    <li>hash two value 2</li>
    <li>hash two value 1</li>
    </ul>
    </ul>



    You'll note the order is NOT preserved as I'm not using Tie::IxHash.

    Anyway, play with the script portion to get a feel for what is going on.
    Add/Remove hash refs, whatever.

    Once the concept starts sinking in you will have taken a major step in
    understanding/using Perl.

    I read somewhere once that if you are not using hashes you are not doing
    Perl.

    Spot on.

    \s
    Steve, Aug 22, 2010
    #12
  13. Steve

    Steve Guest

    On 08/22/2010 07:19 AM, Tuxedo wrote:
    > Steve wrote:
    >
    >> On 08/21/2010 03:32 PM, Tuxedo wrote:
    >>> Steve wrote:
    >>>
    >>>> On 08/21/2010 02:04 PM, Tuxedo wrote:
    >>>>> I have a question about how to generate a multi-level (nested) list
    >>>>> structure by perl. I currently have a 2-level
    >>>>> <ul><li><ul><li></li></ul></li></ul> structure produced via a perl
    >>>>> script, which works fine for its purpose. An example HTML output by
    >>>>> the existing script is:
    >>>>>
    >>>>> <ul>
    >>>>> <li><a href=subject_1.0.html>Subject 1.0</a>
    >>>>> <ul>
    >>>>> <li><a href=page_1.1.html>Page 1.1</a></li>
    >>>>> <li><a href=page_1.2.html>Page 1.2</a></li>
    >>>>> <li><a href=page_1.3.html>Page 1.3</a></li>
    >>>>> </ul>
    >>>>> </li>
    >>>>> </ul>
    >>>>>
    >>>>> There's more non-relevant code that I've stripped for a bit of
    >>>>> clarity, such as CSS etc. In fact, the actual HTML code is largely
    >>>>> irrelavant. Anyway, a barebone version of the perl procedure
    >>>>> generating the above is:
    >>>>>
    >>>>> #!/usr/bin/perl -w
    >>>>>
    >>>>> use Tie::IxHash;
    >>>>> use strict;
    >>>>> use warnings;
    >>>>>
    >>>>> my $object1 = tie my %listoflinks, "Tie::IxHash";
    >>>>>
    >>>>> %listoflinks = ('subject_1.0.html', => 'Subject 1.0',
    >>>>> 'page1.1.html', => 'Page 1.1',
    >>>>> 'page1.2.html', => 'Page 1.2',
    >>>>> 'page1.3.html', => 'Page 1.3');
    >>>>>
    >>>>> for (\%listoflinks) {
    >>>>> my $firstkey = each %$_;
    >>>>>
    >>>>> print "<ul>\n"; # open 1st UL
    >>>>>
    >>>>> print "<li><a href=$firstkey>$listoflinks{$firstkey}</a>\n"; # open
    >>>>> 1st LI
    >>>>>
    >>>>> print "<ul>\n"; # open nested UL
    >>>>>
    >>>>> while ( local $_ = each %$_ ) {
    >>>>> { print "<li><a href=$_>$listoflinks{$_}</a></li> \n" } # print
    >>>>> some LI's }
    >>>>>
    >>>>> print "</ul>\n"; # close nested UL
    >>>>> print "</li>\n"; # close first LI
    >>>>> print "</ul>\n"; # close first UL
    >>>>>
    >>>>> }
    >>>>>
    >>>>> The above procedure was put together with good help from this group
    >>>>> ages ago. As mentioned, the code takes care of the 2-level list
    >>>>> structure and does so by fetching the $firstkey from the array entries
    >>>>> or LoH and inserting the needed opening and closing UL's and LI's in
    >>>>> the right places.
    >>>>>
    >>>>> However, I'm not quite sure how to change the script to generate a
    >>>>> third level, such as:
    >>>>>
    >>>>> <ul>
    >>>>> <li><a href=subject_1.0.html>Subject 1.0</a>
    >>>>> <ul>
    >>>>> <li><a href=page_1.1.html>Page 1.1</a></li>
    >>>>> <li><a href=page_1.2.html>Page 1.2</a></li>
    >>>>> <li><a href=page_1.3.html>Page 1.3</a></li>
    >>>>> <li><a href=subject_2.0.html>Subject 2.0</a>
    >>>>> <ul>
    >>>>> <li><a href=page_2.1.html>Page 2.1</a></li>
    >>>>> <li><a href=page_2.1.html>Page 2.2</a></li>
    >>>>> </ul>
    >>>>> </li>
    >>>>> </ul>
    >>>>> </li>
    >>>>> </ul>
    >>>>>
    >>>>> Or for example, the same structure, with another two second-level list
    >>>>> items at the end:
    >>>>>
    >>>>> <ul>
    >>>>> <li><a href=subject_1.0.html>Subject 1.0</a>
    >>>>> <ul>
    >>>>> <li><a href=page_1.1.html>Page 1.1</a></li>
    >>>>> <li><a href=page_1.2.html>Page 1.2</a></li>
    >>>>> <li><a href=page_1.3.html>Page 1.3</a></li>
    >>>>> <li><a href=subject_2.0.html>Subject 2.0</a>
    >>>>> <ul>
    >>>>> <li><a href=page_2.1.html>Page 2.1</a></li>
    >>>>> <li><a href=page_2.1.html>Page 2.2</a></li>
    >>>>> </ul>
    >>>>> </li>
    >>>>> <li><a href=page_1.4.html>Page 1.4</a></li>
    >>>>> <li><a href=page_1.5.html>Page 1.5</a></li>
    >>>>> </ul>
    >>>>> </li>
    >>>>> </ul>
    >>>>>
    >>>>> Naturally a different array structure would be required in my
    >>>>> %listoflinks to output the above. Any advise or examples how this may
    >>>>> be pieced together would be most helpful.
    >>>>>
    >>>>> Perhaps someone has a procedure in use that does something similar
    >>>>> already?
    >>>>>
    >>>>> Many thanks,
    >>>>> Tuxedo
    >>>>>
    >>>>> NB: System load efficiency is not an issue, as the procedure will run
    >>>>> only occasionally on a local machine to generate HTML sent onto a web
    >>>>> server in static format. In other words, the script will not run
    >>>>> against any real web page requests. The procedure is simply meant to
    >>>>> be an easy maintenance tool.
    >>>>>
    >>>>>
    >>>>
    >>>> I use recursive routines a *lot* in printing out nested data
    >>>> structures, and they are your friend in cases like this...
    >>>>
    >>>> The below is:
    >>>> 1) not tested in any way,
    >>>> 2) may not even compile,
    >>>> 3) and is just a concept.
    >>>>
    >>>> %hash = ( whatever, too lazy to make one );
    >>>>
    >>>> recurse_hash( \%hash );
    >>>>
    >>>> sub recurse_hash {
    >>>> my $refhash = shift;
    >>>> $refhash or return '';
    >>>>
    >>>> print "<ul>\n";
    >>>>
    >>>> while( keys %{$refhash} ){
    >>>> if( ref $refhash->{$_} eq 'HASH' ){
    >>>> recurse_hash( $refhash->{$_} );
    >>>> }
    >>>> else{
    >>>> print "<li>$refhash->{$_}</li>\n";
    >>>> }
    >>>> }
    >>>>
    >>>> print "</ul>\n";
    >>>> }
    >>>>
    >>>> The beauty of a recursive is it flat doesn't matter how many levels
    >>>> deep the data structure is.
    >>>>
    >>>> The downside is it flat doesn't matter how many levels deep the
    >>>> recursive 'thinks' the data structure is and sloppy programming can
    >>>> bite you big time..... infinite recursion anyone?
    >>>>
    >>>> hth,
    >>>>
    >>>> \s
    >>>>
    >>>>
    >>>
    >>> Thanks for the above solution! However, it is a bit difficult for me to
    >>> figure exactly how the %hash = (part may be composed) to generate a
    >>> multi-level list structure. Any additional pointers anyone?
    >>>
    >>> Tuxedo
    >>>
    >>>
    >>>

    >>
    >> Well.....
    >>
    >> my %hash = (
    >> key1 => { subkey => 'value',
    >> subhash => {
    >> subsubkey1 => 'value',
    >> subsubkey2 => 'another value',
    >> },
    >> },
    >> key2 => 'value',
    >> etc => {
    >> },
    >>
    >> );
    >>
    >> But, 'more better' would be to go a reliable (and vetted) source like:
    >>
    >> http://perldoc.perl.org/perldsc.html
    >>
    >> hth,
    >>
    >> \s

    >
    >
    > Thanks for the hash example and perldoc resource. However, it's still a bit
    > confusing. To gain a bit further understanding I tried to run your script
    > 'as is' but it failed to compile, as of course you warned me it may do. In
    > saving your script as a file named testrun.pl and running it, the following
    > errors are repeatedly returned to the shell until I hit Ctrl+C:
    >
    > <li></li>
    > Use of uninitialized value in hash element at ./testrun.pl line 27.
    > Use of uninitialized value in hash element at ./testrun.pl line 31.
    > Use of uninitialized value in concatenation (.) or string at ./testrun.pl
    > line 31.
    > <li></li>
    > Use of uninitialized value in hash element at ./testrun.pl line 27.
    > Use of uninitialized value in hash element at ./testrun.pl line 31.
    > Use of uninitialized value in concatenation (.) or string at ./testrun.pl
    > line 31.
    > <li></li>
    >
    > etc.
    >
    > Unfortunately I do not understand the meaning of the above errors and if I
    > redirect the output to a file, like in ./testrun.pl> file.txt, the file
    > contains a long list of empty<li></li> containers after an opening<ul>:
    >
    > <ul>
    > <li></li>
    > <li></li>
    > <li></li>
    > <li></li>
    > <li></li>
    > <li></li>
    > <li></li>
    > <li></li>
    > <li></li>
    > <li></li>
    >
    > etc...
    >
    > Below is the exact copy of what I tried to run:
    >
    > #!/usr/bin/perl -w
    >
    > use strict;
    > use warnings;
    >
    > my %hash = (
    > key1 => { subkey => 'value',
    > subhash => {
    > subsubkey1 => 'value',
    > subsubkey2 => 'another value',
    > },
    > },
    > key2 => 'value',
    >
    > );
    >
    >
    > recurse_hash( \%hash );
    >
    > sub recurse_hash {
    > my $refhash = shift;
    > $refhash or return '';
    >
    > print "<ul>\n";
    >
    > while( keys %{$refhash} ){
    > if( ref $refhash->{$_} eq 'HASH' ){
    > recurse_hash( $refhash->{$_} );
    > }
    > else{
    > print "<li>$refhash->{$_}</li>\n";
    > }
    > }
    >
    > print "</ul>\n";
    > }
    >
    > Anyone knows where the error(s) in the above procedure are?
    >
    > Thanks again,
    > Tuxedo
    >
    >
    >


    OK, here:
    1) tested
    2) compiles
    3) works


    #! /usr/bin/perl

    use warnings;
    use strict;

    my %one = (
    onek1v1 => 'hash one value 1',
    onek2v1 => 'hash one value 2',
    );

    my %oneref = (
    onerefk1v1 => { anotherlevel => 'hash one down two' },
    onerefval => 'hash one value down one',
    );

    $one{'downone'} = \%oneref;

    my %two = (
    twok1v1 => 'hash two value 1',
    twok2v1 => 'hash two value 2',
    );

    my %three = (
    threek1v1 => 'hash three value 1',
    threek2v1 => 'hash three value 2',
    );

    my %main_hash = (
    one => \%one,
    two => \%two,
    three => \%three,
    );

    recurse_hash( \%main_hash );

    our $spct = 0; ## track leading spaces count

    sub recurse_hash {

    my $refhash = shift;
    $refhash or return '';

    $spct and print ' ' x $spct; # spacecount x spacespace

    print "<ul>\n";

    $spct += 1;

    for( keys %{$refhash} ){

    if( ref $refhash->{$_} eq 'HASH' ){

    $spct += 1;

    recurse_hash( $refhash->{$_} );

    $spct -= 1;
    }
    else{

    $spct+= 1;
    print ' ' x $spct;

    print "<li>$refhash->{$_}</li>\n";

    $spct -= 1;
    }
    }

    $spct -= 1;

    print ' ' x $spct;

    print "</ul>\n";

    }

    exit;


    Command line Output:

    <ul>
    <ul>
    <li>hash three value 1</li>
    <li>hash three value 2</li>
    </ul>
    <ul>
    <li>hash one value 2</li>
    <ul>
    <li>hash one value down one</li>
    <ul>
    <li>hash one down two</li>
    </ul>
    </ul>
    <li>hash one value 1</li>
    </ul>
    <ul>
    <li>hash two value 2</li>
    <li>hash two value 1</li>
    </ul>
    </ul>



    You'll note the order is NOT preserved as I'm not using Tie::IxHash.

    Anyway, play with the script portion to get a feel for what is going on.
    Add/Remove hash refs, whatever.

    Once the concept starts sinking in you will have taken a major step in
    understanding/using Perl.

    I read somewhere once that if you are not using hashes you are not doing
    Perl.

    Spot on.

    \s
    Steve, Aug 22, 2010
    #13
  14. Steve

    Steve Guest

    On 08/22/2010 10:17 AM, Tuxedo wrote:
    > Uri Guttman wrote:
    >
    >>>>>>> "c" == ccc31807<> writes:

    >>
    >> c> On Aug 21, 3:04 pm, Tuxedo<> wrote:
    >> >> I have a question about how to generate a multi-level (nested) list
    >> >> structure by perl. I currently have a 2-level
    >> >> <ul><li><ul><li></li></ul></li></ul> structure produced via a perl
    >> >> script, which works fine for its purpose. An example HTML output by
    >> >> the existing script is:

    >>
    >> c> Mark Jason Dominus, in 'Higher Order Perl' has a section on parsing
    >> c> HTML in chapter 1. You can download the book over the internet, but
    >> c> it's well worth buying, and I would encourage you to do so.
    >>
    >> the OP isn't parsing but generating html. parsing it should be done with
    >> a module. generating it is done well with templates but he still needs
    >> to learn data structures to work with them. regardless of the
    >> technology, nested html needs nested data which means perl data
    >> structures. they are used in some many perl programs that they are
    >> critical to learn early one. perlreftut, perldsc and perllol are
    >> required reading from the perl docs.
    >>
    >> uri
    >>

    >
    > Will look into perlreftut, perldsc and perllol. My task may seem trivial,
    > but as you say, the relevant data structures are needed, which makes this
    > one a hard nut to crack without a fairly deep level of perl knowledge.
    >
    > Tuxedo



    Uri is right in his response that you *must* learn to deal with complex
    data structures.

    I've been using Perl to generate web pages since the mid '90's and I can
    promise you that if you take the time to learn how to deal with nested
    data, how to access it, and how to create it, you will be amazed at how
    much simpler your job becomes.

    So, suck it up and go for it. It will only hurt for a little while. :)

    \s
    Steve, Aug 22, 2010
    #14
  15. Steve

    Uri Guttman Guest

    >>>>> "T" == Tuxedo <> writes:

    T> Uri Guttman wrote:
    >>
    >> the OP isn't parsing but generating html. parsing it should be done with
    >> a module. generating it is done well with templates but he still needs
    >> to learn data structures to work with them. regardless of the
    >> technology, nested html needs nested data which means perl data
    >> structures. they are used in some many perl programs that they are
    >> critical to learn early one. perlreftut, perldsc and perllol are
    >> required reading from the perl docs.


    T> Will look into perlreftut, perldsc and perllol. My task may seem trivial,
    T> but as you say, the relevant data structures are needed, which makes this
    T> one a hard nut to crack without a fairly deep level of perl knowledge.

    i consider perl refs and data structure mid-level perl and not deep
    knowledge. they aren't that hard to learn and they are used all the time
    which make them important to learn.

    as for templating html, there are many choices. i, of course, recommend
    Template::Simple which you can learn quickly and will help in this
    task. regardless of the method you need to learn perl data structures.

    uri

    --
    Uri Guttman ------ -------- http://www.sysarch.com --
    ----- Perl Code Review , Architecture, Development, Training, Support ------
    --------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
    Uri Guttman, Aug 22, 2010
    #15
  16. Steve

    Guest

    On Sat, 21 Aug 2010 21:04:28 +0200, Tuxedo <> wrote:

    >I have a question about how to generate a multi-level (nested) list
    >structure by perl. I currently have a 2-level
    ><ul><li><ul><li></li></ul></li></ul> structure produced via a perl script,
    >which works fine for its purpose. An example HTML output by the existing
    >script is:
    >
    ><ul>
    > <li><a href=subject_1.0.html>Subject 1.0</a>
    > <ul>
    > <li><a href=page_1.1.html>Page 1.1</a></li>
    > <li><a href=page_1.2.html>Page 1.2</a></li>
    > <li><a href=page_1.3.html>Page 1.3</a></li>
    > </ul>
    > </li>
    ></ul>
    >


    I don't have Tie::IxHash and it is not part of the core.
    After commenting it out and running the code, it prints:

    <ul>
    <li><a href=page1.3.html>Page 1.3</a>
    <ul>
    <li><a href=subject_1.0.html>Subject 1.0</a></li>
    <li><a href=page1.2.html>Page 1.2</a></li>
    <li><a href=page1.1.html>Page 1.1</a></li>
    </ul>
    </li>
    </ul>

    This doesen't look like your output to me.

    >There's more non-relevant code that I've stripped for a bit of clarity,
    >such as CSS etc. In fact, the actual HTML code is largely irrelavant.
    >Anyway, a barebone version of the perl procedure generating the above is:
    >
    >#!/usr/bin/perl -w
    >
    >use Tie::IxHash;
    >use strict;
    >use warnings;
    >
    >my $object1 = tie my %listoflinks, "Tie::IxHash";
    >
    >%listoflinks = ('subject_1.0.html', => 'Subject 1.0',
    > 'page1.1.html', => 'Page 1.1',
    > 'page1.2.html', => 'Page 1.2',
    > 'page1.3.html', => 'Page 1.3');
    >
    >for (\%listoflinks) {
    >my $firstkey = each %$_;
    >
    >print "<ul>\n"; # open 1st UL
    >
    >print "<li><a href=$firstkey>$listoflinks{$firstkey}</a>\n"; # open 1st LI
    >
    >print "<ul>\n"; # open nested UL
    >
    >while ( local $_ = each %$_ ) {
    > { print "<li><a href=$_>$listoflinks{$_}</a></li> \n" } # print some LI's
    > }
    >
    >print "</ul>\n"; # close nested UL
    >print "</li>\n"; # close first LI
    >print "</ul>\n"; # close first UL
    >
    >}
    >
    >The above procedure was put together with good help from this group ages
    >ago.


    This looks to be fairly junky code. There is nothing but a linear
    generation of html. It might as well have been put together with a
    here doc statement.

    >As mentioned, the code takes care of the 2-level list structure and
    >does so by fetching the $firstkey from the array entries or LoH and
    >inserting the needed opening and closing UL's and LI's in the right places.
    >
    >However, I'm not quite sure how to change the script to generate a third
    >level, such as:
    >


    You havent even been to the second generation, so far its
    really been 1 dimensional.

    ><ul>
    > <li><a href=subject_1.0.html>Subject 1.0</a>
    > <ul>
    > <li><a href=page_1.1.html>Page 1.1</a></li>
    > <li><a href=page_1.2.html>Page 1.2</a></li>
    > <li><a href=page_1.3.html>Page 1.3</a></li>
    > <li><a href=subject_2.0.html>Subject 2.0</a>
    > <ul>
    > <li><a href=page_2.1.html>Page 2.1</a></li>
    > <li><a href=page_2.1.html>Page 2.2</a></li>
    > </ul>
    > </li>
    > </ul>
    > </li>
    ></ul>
    >
    >Or for example, the same structure, with another two second-level list
    >items at the end:
    >
    ><ul>
    > <li><a href=subject_1.0.html>Subject 1.0</a>
    > <ul>
    > <li><a href=page_1.1.html>Page 1.1</a></li>
    > <li><a href=page_1.2.html>Page 1.2</a></li>
    > <li><a href=page_1.3.html>Page 1.3</a></li>
    > <li><a href=subject_2.0.html>Subject 2.0</a>
    > <ul>
    > <li><a href=page_2.1.html>Page 2.1</a></li>
    > <li><a href=page_2.1.html>Page 2.2</a></li>
    > </ul>
    > </li>
    > <li><a href=page_1.4.html>Page 1.4</a></li>
    > <li><a href=page_1.5.html>Page 1.5</a></li>
    > </ul>
    > </li>
    ></ul>
    >
    >Naturally a different array structure would be required in my %listoflinks
    >to output the above. Any advise or examples how this may be pieced together
    >would be most helpful.
    >
    >Perhaps someone has a procedure in use that does something similar already?


    If you want to put together a dynamic html generator, you
    will need to write a mini engine to do that.

    -sln
    , Aug 22, 2010
    #16
  17. Steve

    Tuxedo Guest

    wrote:

    > On Sat, 21 Aug 2010 21:04:28 +0200, Tuxedo <> wrote:
    >
    > >I have a question about how to generate a multi-level (nested) list
    > >structure by perl. I currently have a 2-level
    > ><ul><li><ul><li></li></ul></li></ul> structure produced via a perl
    > >script, which works fine for its purpose. An example HTML output by the
    > >existing script is:
    > >
    > ><ul>
    > > <li><a href=subject_1.0.html>Subject 1.0</a>
    > > <ul>
    > > <li><a href=page_1.1.html>Page 1.1</a></li>
    > > <li><a href=page_1.2.html>Page 1.2</a></li>
    > > <li><a href=page_1.3.html>Page 1.3</a></li>
    > > </ul>
    > > </li>
    > ></ul>
    > >

    >
    > I don't have Tie::IxHash and it is not part of the core.
    > After commenting it out and running the code, it prints:
    >
    > <ul>
    > <li><a href=page1.3.html>Page 1.3</a>
    > <ul>
    > <li><a href=subject_1.0.html>Subject 1.0</a></li>
    > <li><a href=page1.2.html>Page 1.2</a></li>
    > <li><a href=page1.1.html>Page 1.1</a></li>
    > </ul>
    > </li>
    > </ul>
    >
    > This doesen't look like your output to me.


    Yes, because Tie::IxHash puts things in order. Without, %listoflinks will
    appear in a seemingly random order.

    >
    > >There's more non-relevant code that I've stripped for a bit of clarity,
    > >such as CSS etc. In fact, the actual HTML code is largely irrelavant.
    > >Anyway, a barebone version of the perl procedure generating the above is:
    > >
    > >#!/usr/bin/perl -w
    > >
    > >use Tie::IxHash;
    > >use strict;
    > >use warnings;
    > >
    > >my $object1 = tie my %listoflinks, "Tie::IxHash";
    > >
    > >%listoflinks = ('subject_1.0.html', => 'Subject 1.0',
    > > 'page1.1.html', => 'Page 1.1',
    > > 'page1.2.html', => 'Page 1.2',
    > > 'page1.3.html', => 'Page 1.3');
    > >
    > >for (\%listoflinks) {
    > >my $firstkey = each %$_;
    > >
    > >print "<ul>\n"; # open 1st UL
    > >
    > >print "<li><a href=$firstkey>$listoflinks{$firstkey}</a>\n"; # open 1st
    > >LI
    > >
    > >print "<ul>\n"; # open nested UL
    > >
    > >while ( local $_ = each %$_ ) {
    > > { print "<li><a href=$_>$listoflinks{$_}</a></li> \n" } # print some
    > > LI's }
    > >
    > >print "</ul>\n"; # close nested UL
    > >print "</li>\n"; # close first LI
    > >print "</ul>\n"; # close first UL
    > >
    > >}
    > >
    > >The above procedure was put together with good help from this group ages
    > >ago.

    >
    > This looks to be fairly junky code. There is nothing but a linear
    > generation of html. It might as well have been put together with a
    > here doc statement.


    It fulfilled the purpose it was meant to serve, call it junk or not.

    > >As mentioned, the code takes care of the 2-level list structure and
    > >does so by fetching the $firstkey from the array entries or LoH and
    > >inserting the needed opening and closing UL's and LI's in the right
    > >places.
    > >
    > >However, I'm not quite sure how to change the script to generate a third
    > >level, such as:
    > >

    >
    > You havent even been to the second generation, so far its
    > really been 1 dimensional.


    Counting the ground floor so to speak, the structure produced by the
    existing script was the following:

    <ul>
    <li>first
    <ul>
    <li>second</li>
    </ul>
    </li>
    </ul>

    Instead what I need is:

    <ul>
    <li>first
    <ul>
    <li>second
    <ul>
    <li>third</li>
    </ul>
    </li>
    </ul>
    </li>
    </ul>

    The current script is not capable of two floors, partly because of the data
    structure and the fact that it simply fetches the firstkey to insert the
    relevant HTML code in the right places.

    >
    > ><ul>
    > > <li><a href=subject_1.0.html>Subject 1.0</a>
    > > <ul>
    > > <li><a href=page_1.1.html>Page 1.1</a></li>
    > > <li><a href=page_1.2.html>Page 1.2</a></li>
    > > <li><a href=page_1.3.html>Page 1.3</a></li>
    > > <li><a href=subject_2.0.html>Subject 2.0</a>
    > > <ul>
    > > <li><a href=page_2.1.html>Page 2.1</a></li>
    > > <li><a href=page_2.1.html>Page 2.2</a></li>
    > > </ul>
    > > </li>
    > > </ul>
    > > </li>
    > ></ul>
    > >
    > >Or for example, the same structure, with another two second-level list
    > >items at the end:
    > >
    > ><ul>
    > > <li><a href=subject_1.0.html>Subject 1.0</a>
    > > <ul>
    > > <li><a href=page_1.1.html>Page 1.1</a></li>
    > > <li><a href=page_1.2.html>Page 1.2</a></li>
    > > <li><a href=page_1.3.html>Page 1.3</a></li>
    > > <li><a href=subject_2.0.html>Subject 2.0</a>
    > > <ul>
    > > <li><a href=page_2.1.html>Page 2.1</a></li>
    > > <li><a href=page_2.1.html>Page 2.2</a></li>
    > > </ul>
    > > </li>
    > > <li><a href=page_1.4.html>Page 1.4</a></li>
    > > <li><a href=page_1.5.html>Page 1.5</a></li>
    > > </ul>
    > > </li>
    > ></ul>
    > >
    > >Naturally a different array structure would be required in my
    > >%listoflinks to output the above. Any advise or examples how this may be
    > >pieced together would be most helpful.
    > >
    > >Perhaps someone has a procedure in use that does something similar
    > >already?

    >
    > If you want to put together a dynamic html generator, you
    > will need to write a mini engine to do that.


    Yes, it sounds like a need a nested list engine of the best make :)

    Tuxedo

    >
    > -sln
    Tuxedo, Aug 22, 2010
    #17
  18. Steve

    Tuxedo Guest

    Steve wrote:

    > On 08/22/2010 07:19 AM, Tuxedo wrote:
    > > Steve wrote:
    > >
    > >> On 08/21/2010 03:32 PM, Tuxedo wrote:
    > >>> Steve wrote:
    > >>>
    > >>>> On 08/21/2010 02:04 PM, Tuxedo wrote:
    > >>>>> I have a question about how to generate a multi-level (nested) list
    > >>>>> structure by perl. I currently have a 2-level
    > >>>>> <ul><li><ul><li></li></ul></li></ul> structure produced via a
    > >>>>> perl script, which works fine for its purpose. An example HTML
    > >>>>> output by the existing script is:
    > >>>>>
    > >>>>> <ul>
    > >>>>> <li><a href=subject_1.0.html>Subject 1.0</a>
    > >>>>> <ul>
    > >>>>> <li><a href=page_1.1.html>Page 1.1</a></li>
    > >>>>> <li><a href=page_1.2.html>Page 1.2</a></li>
    > >>>>> <li><a href=page_1.3.html>Page 1.3</a></li>
    > >>>>> </ul>
    > >>>>> </li>
    > >>>>> </ul>
    > >>>>>
    > >>>>> There's more non-relevant code that I've stripped for a bit of
    > >>>>> clarity, such as CSS etc. In fact, the actual HTML code is largely
    > >>>>> irrelavant. Anyway, a barebone version of the perl procedure
    > >>>>> generating the above is:
    > >>>>>
    > >>>>> #!/usr/bin/perl -w
    > >>>>>
    > >>>>> use Tie::IxHash;
    > >>>>> use strict;
    > >>>>> use warnings;
    > >>>>>
    > >>>>> my $object1 = tie my %listoflinks, "Tie::IxHash";
    > >>>>>
    > >>>>> %listoflinks = ('subject_1.0.html', => 'Subject 1.0',
    > >>>>> 'page1.1.html', => 'Page 1.1',
    > >>>>> 'page1.2.html', => 'Page 1.2',
    > >>>>> 'page1.3.html', => 'Page 1.3');
    > >>>>>
    > >>>>> for (\%listoflinks) {
    > >>>>> my $firstkey = each %$_;
    > >>>>>
    > >>>>> print "<ul>\n"; # open 1st UL
    > >>>>>
    > >>>>> print "<li><a href=$firstkey>$listoflinks{$firstkey}</a>\n"; # open
    > >>>>> 1st LI
    > >>>>>
    > >>>>> print "<ul>\n"; # open nested UL
    > >>>>>
    > >>>>> while ( local $_ = each %$_ ) {
    > >>>>> { print "<li><a href=$_>$listoflinks{$_}</a></li> \n" } #
    > >>>>> print some LI's }
    > >>>>>
    > >>>>> print "</ul>\n"; # close nested UL
    > >>>>> print "</li>\n"; # close first LI
    > >>>>> print "</ul>\n"; # close first UL
    > >>>>>
    > >>>>> }
    > >>>>>
    > >>>>> The above procedure was put together with good help from this group
    > >>>>> ages ago. As mentioned, the code takes care of the 2-level list
    > >>>>> structure and does so by fetching the $firstkey from the array
    > >>>>> entries or LoH and inserting the needed opening and closing UL's and
    > >>>>> LI's in the right places.
    > >>>>>
    > >>>>> However, I'm not quite sure how to change the script to generate a
    > >>>>> third level, such as:
    > >>>>>
    > >>>>> <ul>
    > >>>>> <li><a href=subject_1.0.html>Subject 1.0</a>
    > >>>>> <ul>
    > >>>>> <li><a href=page_1.1.html>Page 1.1</a></li>
    > >>>>> <li><a href=page_1.2.html>Page 1.2</a></li>
    > >>>>> <li><a href=page_1.3.html>Page 1.3</a></li>
    > >>>>> <li><a href=subject_2.0.html>Subject 2.0</a>
    > >>>>> <ul>
    > >>>>> <li><a href=page_2.1.html>Page 2.1</a></li>
    > >>>>> <li><a href=page_2.1.html>Page 2.2</a></li>
    > >>>>> </ul>
    > >>>>> </li>
    > >>>>> </ul>
    > >>>>> </li>
    > >>>>> </ul>
    > >>>>>
    > >>>>> Or for example, the same structure, with another two second-level
    > >>>>> list items at the end:
    > >>>>>
    > >>>>> <ul>
    > >>>>> <li><a href=subject_1.0.html>Subject 1.0</a>
    > >>>>> <ul>
    > >>>>> <li><a href=page_1.1.html>Page 1.1</a></li>
    > >>>>> <li><a href=page_1.2.html>Page 1.2</a></li>
    > >>>>> <li><a href=page_1.3.html>Page 1.3</a></li>
    > >>>>> <li><a href=subject_2.0.html>Subject 2.0</a>
    > >>>>> <ul>
    > >>>>> <li><a href=page_2.1.html>Page 2.1</a></li>
    > >>>>> <li><a href=page_2.1.html>Page 2.2</a></li>
    > >>>>> </ul>
    > >>>>> </li>
    > >>>>> <li><a href=page_1.4.html>Page 1.4</a></li>
    > >>>>> <li><a href=page_1.5.html>Page 1.5</a></li>
    > >>>>> </ul>
    > >>>>> </li>
    > >>>>> </ul>
    > >>>>>
    > >>>>> Naturally a different array structure would be required in my
    > >>>>> %listoflinks to output the above. Any advise or examples how this
    > >>>>> may be pieced together would be most helpful.
    > >>>>>
    > >>>>> Perhaps someone has a procedure in use that does something similar
    > >>>>> already?
    > >>>>>
    > >>>>> Many thanks,
    > >>>>> Tuxedo
    > >>>>>
    > >>>>> NB: System load efficiency is not an issue, as the procedure will
    > >>>>> run only occasionally on a local machine to generate HTML sent onto
    > >>>>> a web server in static format. In other words, the script will not
    > >>>>> run against any real web page requests. The procedure is simply
    > >>>>> meant to be an easy maintenance tool.
    > >>>>>
    > >>>>>
    > >>>>
    > >>>> I use recursive routines a *lot* in printing out nested data
    > >>>> structures, and they are your friend in cases like this...
    > >>>>
    > >>>> The below is:
    > >>>> 1) not tested in any way,
    > >>>> 2) may not even compile,
    > >>>> 3) and is just a concept.
    > >>>>
    > >>>> %hash = ( whatever, too lazy to make one );
    > >>>>
    > >>>> recurse_hash( \%hash );
    > >>>>
    > >>>> sub recurse_hash {
    > >>>> my $refhash = shift;
    > >>>> $refhash or return '';
    > >>>>
    > >>>> print "<ul>\n";
    > >>>>
    > >>>> while( keys %{$refhash} ){
    > >>>> if( ref $refhash->{$_} eq 'HASH' ){
    > >>>> recurse_hash( $refhash->{$_} );
    > >>>> }
    > >>>> else{
    > >>>> print "<li>$refhash->{$_}</li>\n";
    > >>>> }
    > >>>> }
    > >>>>
    > >>>> print "</ul>\n";
    > >>>> }
    > >>>>
    > >>>> The beauty of a recursive is it flat doesn't matter how many levels
    > >>>> deep the data structure is.
    > >>>>
    > >>>> The downside is it flat doesn't matter how many levels deep the
    > >>>> recursive 'thinks' the data structure is and sloppy programming can
    > >>>> bite you big time..... infinite recursion anyone?
    > >>>>
    > >>>> hth,
    > >>>>
    > >>>> \s
    > >>>>
    > >>>>
    > >>>
    > >>> Thanks for the above solution! However, it is a bit difficult for me
    > >>> to figure exactly how the %hash = (part may be composed) to generate a
    > >>> multi-level list structure. Any additional pointers anyone?
    > >>>
    > >>> Tuxedo
    > >>>
    > >>>
    > >>>
    > >>
    > >> Well.....
    > >>
    > >> my %hash = (
    > >> key1 => { subkey => 'value',
    > >> subhash => {
    > >> subsubkey1 => 'value',
    > >> subsubkey2 => 'another value',
    > >> },
    > >> },
    > >> key2 => 'value',
    > >> etc => {
    > >> },
    > >>
    > >> );
    > >>
    > >> But, 'more better' would be to go a reliable (and vetted) source like:
    > >>
    > >> http://perldoc.perl.org/perldsc.html
    > >>
    > >> hth,
    > >>
    > >> \s

    > >
    > >
    > > Thanks for the hash example and perldoc resource. However, it's still a
    > > bit confusing. To gain a bit further understanding I tried to run your
    > > script 'as is' but it failed to compile, as of course you warned me it
    > > may do. In saving your script as a file named testrun.pl and running it,
    > > the following errors are repeatedly returned to the shell until I hit
    > > Ctrl+C:
    > >
    > > <li></li>
    > > Use of uninitialized value in hash element at ./testrun.pl line 27.
    > > Use of uninitialized value in hash element at ./testrun.pl line 31.
    > > Use of uninitialized value in concatenation (.) or string at
    > > ./testrun.pl line 31.
    > > <li></li>
    > > Use of uninitialized value in hash element at ./testrun.pl line 27.
    > > Use of uninitialized value in hash element at ./testrun.pl line 31.
    > > Use of uninitialized value in concatenation (.) or string at
    > > ./testrun.pl line 31.
    > > <li></li>
    > >
    > > etc.
    > >
    > > Unfortunately I do not understand the meaning of the above errors and if
    > > I
    > > redirect the output to a file, like in ./testrun.pl> file.txt, the file
    > > contains a long list of empty<li></li> containers after an opening<ul>:
    > >
    > > <ul>
    > > <li></li>
    > > <li></li>
    > > <li></li>
    > > <li></li>
    > > <li></li>
    > > <li></li>
    > > <li></li>
    > > <li></li>
    > > <li></li>
    > > <li></li>
    > >
    > > etc...
    > >
    > > Below is the exact copy of what I tried to run:
    > >
    > > #!/usr/bin/perl -w
    > >
    > > use strict;
    > > use warnings;
    > >
    > > my %hash = (
    > > key1 => { subkey => 'value',
    > > subhash => {
    > > subsubkey1 => 'value',
    > > subsubkey2 => 'another value',
    > > },
    > > },
    > > key2 => 'value',
    > >
    > > );
    > >
    > >
    > > recurse_hash( \%hash );
    > >
    > > sub recurse_hash {
    > > my $refhash = shift;
    > > $refhash or return '';
    > >
    > > print "<ul>\n";
    > >
    > > while( keys %{$refhash} ){
    > > if( ref $refhash->{$_} eq 'HASH' ){
    > > recurse_hash( $refhash->{$_} );
    > > }
    > > else{
    > > print "<li>$refhash->{$_}</li>\n";
    > > }
    > > }
    > >
    > > print "</ul>\n";
    > > }
    > >
    > > Anyone knows where the error(s) in the above procedure are?
    > >
    > > Thanks again,
    > > Tuxedo
    > >
    > >
    > >

    >
    > OK, here:
    > 1) tested
    > 2) compiles
    > 3) works
    >
    >
    > #! /usr/bin/perl
    >
    > use warnings;
    > use strict;
    >
    > my %one = (
    > onek1v1 => 'hash one value 1',
    > onek2v1 => 'hash one value 2',
    > );
    >
    > my %oneref = (
    > onerefk1v1 => { anotherlevel => 'hash one down two' },
    > onerefval => 'hash one value down one',
    > );
    >
    > $one{'downone'} = \%oneref;
    >
    > my %two = (
    > twok1v1 => 'hash two value 1',
    > twok2v1 => 'hash two value 2',
    > );
    >
    > my %three = (
    > threek1v1 => 'hash three value 1',
    > threek2v1 => 'hash three value 2',
    > );
    >
    > my %main_hash = (
    > one => \%one,
    > two => \%two,
    > three => \%three,
    > );
    >
    > recurse_hash( \%main_hash );
    >
    > our $spct = 0; ## track leading spaces count
    >
    > sub recurse_hash {
    >
    > my $refhash = shift;
    > $refhash or return '';
    >
    > $spct and print ' ' x $spct; # spacecount x spacespace
    >
    > print "<ul>\n";
    >
    > $spct += 1;
    >
    > for( keys %{$refhash} ){
    >
    > if( ref $refhash->{$_} eq 'HASH' ){
    >
    > $spct += 1;
    >
    > recurse_hash( $refhash->{$_} );
    >
    > $spct -= 1;
    > }
    > else{
    >
    > $spct+= 1;
    > print ' ' x $spct;
    >
    > print "<li>$refhash->{$_}</li>\n";
    >
    > $spct -= 1;
    > }
    > }
    >
    > $spct -= 1;
    >
    > print ' ' x $spct;
    >
    > print "</ul>\n";
    >
    > }
    >
    > exit;
    >
    >
    > Command line Output:
    >
    > <ul>
    > <ul>
    > <li>hash three value 1</li>
    > <li>hash three value 2</li>
    > </ul>
    > <ul>
    > <li>hash one value 2</li>
    > <ul>
    > <li>hash one value down one</li>
    > <ul>
    > <li>hash one down two</li>
    > </ul>
    > </ul>
    > <li>hash one value 1</li>
    > </ul>
    > <ul>
    > <li>hash two value 2</li>
    > <li>hash two value 1</li>
    > </ul>
    > </ul>
    >
    >
    >
    > You'll note the order is NOT preserved as I'm not using Tie::IxHash.
    >
    > Anyway, play with the script portion to get a feel for what is going on.
    > Add/Remove hash refs, whatever.
    >
    > Once the concept starts sinking in you will have taken a major step in
    > understanding/using Perl.
    >
    > I read somewhere once that if you are not using hashes you are not doing
    > Perl.
    >
    > Spot on.
    >
    > \s



    Thanks for this excellent example!

    The only odd thing I see at first sight is that the first <ul> is not
    followed directly by an <li> at any level, which is the intended structure
    of the particular HTML list. Instead, there is a <ul><ul> structure. I
    think I need to apply Tie::IxHash to see through this a bit better. I will
    tinker with it and will surely find it a useful learning experience :)

    Thanks again,
    Tuxedo
    Tuxedo, Aug 22, 2010
    #18
  19. Steve

    Tuxedo Guest

    Tad McClellan wrote:

    > Tuxedo <> wrote:
    >
    > > 'as is' but it failed to compile,

    >
    >
    > None of the messages you've shown indicate a failure to compile.
    >
    > What makes you think compilation failed?
    >
    >
    > > as of course you warned me it may do. In
    > > saving your script as a file named testrun.pl and running it, the
    > > following errors are repeatedly returned to the shell until I hit
    > > Ctrl+C:
    > >
    > ><li></li>
    > > Use of uninitialized value in hash element at ./testrun.pl line 27.
    > > Use of uninitialized value in hash element at ./testrun.pl line 31.
    > > Use of uninitialized value in concatenation (.) or string at
    > > ./testrun.pl line 31.
    > ><li></li>
    > > Use of uninitialized value in hash element at ./testrun.pl line 27.
    > > Use of uninitialized value in hash element at ./testrun.pl line 31.
    > > Use of uninitialized value in concatenation (.) or string at
    > > ./testrun.pl line 31.

    >
    >
    > None of those are error messages.
    >
    > They are warning messages.
    >
    >
    > > Unfortunately I do not understand the meaning of the above errors

    >
    >
    > Even after looking up the messages in Perl's standard docs?
    >
    > perldoc perldiag


    Yes, warnings. You're right. Will take a note of 'perldoc perldiag'.

    > > and if I
    > > redirect the output to a file, like in ./testrun.pl > file.txt, the file
    > > contains a long list of empty <li></li> containers after an opening
    > > <ul>:

    >
    >
    > If the program ran, then it must have compiled successfully...


    It sure ran, in fact it didn't stop running without Ctrl+C. As with errors
    vs. warnings, just wrong use of terminology on my part.

    Thanks for putting the records straight!

    Tuxedo
    Tuxedo, Aug 22, 2010
    #19
  20. Steve

    Tuxedo Guest

    Uri Guttman wrote:

    > >>>>> "T" == Tuxedo <> writes:

    >
    > T> Uri Guttman wrote:
    > >>
    > >> the OP isn't parsing but generating html. parsing it should be done
    > >> with a module. generating it is done well with templates but he still
    > >> needs to learn data structures to work with them. regardless of the
    > >> technology, nested html needs nested data which means perl data
    > >> structures. they are used in some many perl programs that they are
    > >> critical to learn early one. perlreftut, perldsc and perllol are
    > >> required reading from the perl docs.

    >
    > T> Will look into perlreftut, perldsc and perllol. My task may seem
    > trivial, T> but as you say, the relevant data structures are needed,
    > which makes this T> one a hard nut to crack without a fairly deep level
    > of perl knowledge.
    >
    > i consider perl refs and data structure mid-level perl and not deep
    > knowledge. they aren't that hard to learn and they are used all the time
    > which make them important to learn.
    >
    > as for templating html, there are many choices. i, of course, recommend
    > Template::Simple which you can learn quickly and will help in this
    > task. regardless of the method you need to learn perl data structures.
    >
    > uri
    >


    Point taken! I'm sure even a basic understanding of data structures is a
    requirement to use perl for any advanced programming rather than some kind
    of rudimentary shell like enhancement tool.

    Tuxedo
    Tuxedo, Aug 22, 2010
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    2
    Views:
    442
  2. =?Utf-8?B?Sm9l?=

    page-level vs control-level enableViewState

    =?Utf-8?B?Sm9l?=, Oct 26, 2005, in forum: ASP .Net
    Replies:
    3
    Views:
    2,929
    S. Justin Gengo
    Oct 26, 2005
  3. Replies:
    8
    Views:
    462
  4. pabbu
    Replies:
    8
    Views:
    721
    Marc Boyer
    Nov 7, 2005
  5. John W. Long

    HTML Generation (Next Generation CGI)

    John W. Long, Nov 22, 2003, in forum: Ruby
    Replies:
    4
    Views:
    331
    John W. Long
    Nov 24, 2003
Loading...

Share This Page