Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Re^2: Directory Tree Structure

by Lady_Aleena (Priest)
on Oct 03, 2009 at 21:46 UTC ( [id://799061]=note: print w/replies, xml ) Need Help??


in reply to Re: Directory Tree Structure
in thread Directory Tree Structure

graff,

I know that this is almost 4 years later, but I see a problem with the output of the code. It would cause several HTML validation errors.

If you please look at your output at <LI> examples/html: </LI>. The </li> needs to be down after </ul> after <LI> examples/html/tables: </LI> since the indented unordered list is within the above list item.

I have tried fixing it and will keep trying in the meantime, but so far I have had only a little success.

<ul> <li>Foo level 1 <ul> <li>Foo level 2 <ul> <li>Bar</li> <li>Baz</li> </ul> </li> #This closes Foo level 2 <li>Qux</li> <li>Quux</li> </ul> </li> #This closes Foo level 1 <li>Widget</li> </ul>
Have a nice day!
Lady Aleena

Replies are listed 'Best First'.
Re^3: Directory Tree Structure
by graff (Chancellor) on Oct 04, 2009 at 21:10 UTC
    Lady Aleena,

    Nice to hear from you again. What particular method are you using for html validation? (That is, who says that <ul>...</ul> positioned between </li>...<li> is invalid?) UPDATE: almut's reply clears this up -- I'm wrong, and the markup I posted above is Not Good™.

    I'm somewhat skeptical that the output I posted above constitutes an error in html syntax. Despite knowing that this markup is invalid, it may be worth pointing out that I stuck it into a file surrounded by <html>...</html> and loaded it into Safari and Firefox, and they both render it as I would expect (i.e. as intended). So in that sense at least, it works.

    Having said that, I'll acknowledge that the following layout for the markup also works, and I can well imagine that one or another validator might it has been shown that html validators should insist on this version (even though I don't see it as a necessary condition it seems to work either way):

    <UL> <LI> examples/html: <UL> <LI> examples/html/bars: </LI> <LI> examples/html/headers: </LI> <LI> examples/html/links: </LI> <LI> examples/html/lists: </LI> <LI> examples/html/menus: </LI> <LI> examples/html/rgb: </LI> <LI> examples/html/tables: </LI> </UL> </LI> <LI> examples/ps: <UL> <LI> examples/ps/marks: </LI> </UL> </LI> <LI> examples/splash: <UL> <LI> examples/splash/dropbox: </LI> <LI> examples/splash/frame: </LI> <LI> examples/splash/hair: </LI> <LI> examples/splash/icon: </LI> <LI> examples/splash/menu: </LI> <LI> examples/splash/menubar: </LI> </UL> </LI> </UL>
    If you are having trouble getting the code to output this pattern, show the code you have so far, and we'll see what's up with that.
      who says that <ul>...</ul> positioned between </li>...<li> is invalid?

      W3C Markup Validation Service  :)

      <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" > <title></title> </head> <body> <UL> <LI> examples/html: </LI> <UL> <LI> examples/html/bars: </LI> </UL> <LI> examples/ps: </LI> </UL> </body> </html> --- Validation Output: 1 Error Line 11, Column 6: document type does not allow element "UL" here; ass +uming missing "LI" start-tag

        Ul and ol can only have li elements as children. And what you're doing seems to be trying to insert one list inside another as a list item, so why not put that nested list inside a new list item (owned by the containing list, containing the nested list)?

        (That's the way most people make those CSS drop-down hierarchical menus, too.)

        Maybe it is html 3.2
      graff,

      Here is what I have so far. Unfortunately, I haven't worked out a few things like having it only read the files in the directories and excluding the subdirectories in directory_contents. I am getting duplicates.

      I have been shown a few other things, but haven't quite gotten the kinks worked out of those either.

      #!/usr/bin/perl use strict; use warnings; use diagnostics; use File::Find; use File::Spec; my $rootdir = "C:/Documents and Settings/<my name>/My Documents/fantas +y"; my @files; sub wanted { my $text = $File::Find::name; push @files, $text; return; } sub directory_contents { my ($contents) = @_; my $file_tab = $contents; $file_tab =~ s{$rootdir}{}; my $tab = "\t" x ($file_tab =~ tr{/}{}); my @list = (map("$tab<li>".$_."</li>\n",grep{m/^($contents)\//} @fil +es)); #the grep is where I think I need to put the stop on going lowe +r. return join("",@list); } sub print_directory { my ($file) = @_; my $file_tab = $file; $file_tab =~ s{$rootdir}{}; my $tab = "\t" x ($file_tab =~ tr{/}{}); my $directory = qq{$tab<li>$file\n$tab<ul>\n}.directory_contents($fi +le).qq{$tab</ul>\n$tab</li>\n}; print $directory; } find(\&wanted, $rootdir); foreach my $entry (File::Spec->no_upwards(@files)) { print_directory($entry) if -d $entry; }
      Have a nice day!
      Lady Aleena
        Unfortunately, I haven't worked out a few things like having it only read the files in the directories and excluding the subdirectories in directory_contents. I am getting duplicates.

        Well, you're doing something a little different from the OP in this thread, listing all the data files along with the directories (instead of just the directories), so that does complicate things. To see where you're getting duplication and trouble, I think you'll want to use Data::Dumper 'Dumper'; and step through it with "perl -d". In the debugger, you can do p Dumper($some_variable_or_reference) to see what's happening with the data.

        I think the correct way to make sure that you get the right structure in your output is to have the right structure be created by the "wanted" sub that you pass to File::Find. And that would be HoH, built recursively to have nested hash keys represent the nested directories. A special hash key "./" can be used to hold a reference to an array that contains the actual data files (if any) in a given directory.

        Then for output, you just walk through the structure, indenting and including suitable html tags as you go. (And if you're really going to be outputting html, you should probably use HTML::Entities URI::Escape on the path strings.)

        I cobbled this together based on another old post of mine that had to do with building a recursive hash structure (Re: seeking in hash data structure), and I'll confess that this took me longer than I'd like to admit. (It's tricky business to do recursion right, esp. if you don't do it very often.)

        I'm sure there's one or more modules that could be used to simplify (or replace) this code. You might need to tweak it -- change "/" to "\", etc -- to make it work properly on windows (it works for me on macosx/unix/linux):

        #!/usr/bin/perl use strict; use warnings; use diagnostics; use File::Find; use File::Basename; use HTML::Entities; @ARGV == 1 and -d $ARGV[0] or die "Usage: $0 path_name\n"; ( my $rootdir = shift ) =~ s{(?<!/)$}{/}; # make sure path ends with + "/" my %tree; $tree{$rootdir} = {}; find(\&wanted, $rootdir); print "<html>\n"; print_tree( \%tree, 0 ); print "</html>\n"; sub wanted { local $_ = $File::Find::name; if ( -f ) { # only work on data files (skip directories +) s{\Q$rootdir\E}{}; # remove the rootdir string from the pat +h name load_tree( $tree{$rootdir}, fileparse( $_ )); } } # recursively load the hash structure # (first call gets top-level hashref, and # file name, path from File::Basename::fileparse) sub load_tree { my ( $href, $name, $path ) = @_; my @dirs = split /\//, $path; push @dirs, '.' if ( $dirs[$#dirs] ne '.' ); my $key = shift @dirs; while ( @dirs and $key ne '.' and exists( $$href{"$key/"} )) { $href = $$href{"$key/"}; $key = shift @dirs; } if ( $key ne '.' and ! exists( $$href{"$key/"} )) { $$href{"$key/"} = {}; load_tree( $$href{"$key/"}, $name, join( '/', @dirs, '' )); } elsif ( $key eq '.' ) { push @{$$href{"$key/"}}, $name; } } # recursively print embedded lists sub print_tree { my ( $href, $indent ) = @_; printf( "%s<ul>\n", ' ' x $indent ); $indent++; if ( exists( $$href{'./'} )) { printf( "%s<li>%s</li>\n", ' ' x $indent, encode_entities( $_ + )) for ( @{$$href{'./'}} ); delete $$href{'./'}; } if ( keys %$href ) { for my $subdir ( sort keys %$href ) { printf( "%s<li>%s\n", ' ' x $indent, encode_entities( $su +bdir )); $indent++; print_tree( $$href{$subdir}, $indent ); $indent--; printf( "%s</li>\n", ' ' x $indent ); } } $indent--; printf( "%s</ul>\n", ' ' x $indent ); }
        (Updated to use HTML::Entities instead of URI::Escape -- the latter was a wrong choice)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://799061]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (2)
As of 2024-04-19 18:38 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found