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

I am currently designing a small markup "language" for the use of my web site. Basically I have a perl program that uses a recursive sub to cycle through all of the directories in my web page folder, and whenever it finds the .cui file (the files that hold the actual data) it reads it in and applys a template. The template works by locating the substr #&# and reading the description after it. My perl program then over-writes in the text file with the same name. Here is a small sample .cui file:
   <html>
      #&#header
      #&#open_body
         #&#search_table
      #&#close_body
   <html>
I have two main problems with my program now. One, I want the output HTML to be pretty with the correct tabs. Currently I can half achieve this by using the return value of an index of #&#. The only problem is that the sample open_body file looks roughly like this:
   <body>
      <table>
         <tr>
This means that I am not taking into account the extra tab in for the table or the tr tags. Can anyone suggest a way around this problem? My second problem is that because I am working this process recursivly, there will be different paths to images and links. Without hardcoding, I want to be able to tell how deep I am in the directory structure, and apply the correct number of "../"s. Any help would be greatly appreciated.

Apoc

Replies are listed 'Best First'.
Re (tilly) 1: Creating A Custom Markup
by tilly (Archbishop) on Dec 15, 2001 at 23:32 UTC
    What is wrong with existing markup languages like the customizable ones you get with Text::Template and Template::Toolkit?

    The second in particular already has a utility that handles something suspiciously like your problem.

      I was unaware of Text::Template, so I am looking into applying that instead, however, it still appears that it has a different functionality than what I need. I want to apply files (plural) to a template, not apply a template to a file. Also, what is the name of the utility that you speak of?
        The utility that comes with the Template::Toolkit is called ttree. Before going farther I suggest reading this introduction to using the template toolkit for building websites.

        Remember this. Templating tools are one of the most often re-invented wheels in the Perl world. We have quite a few of them, with very good ones suited to all sorts of different niches. Rather than roll your own I strongly recommend figuring out what your desired feature set is, and then go out and find one that already does that.

Re: Creating A Custom Markup
by chromatic (Archbishop) on Dec 15, 2001 at 23:58 UTC
    I'm not sure exactly what your pretty-printing trouble is, but if you know your token will be at the start of the file, why not keep track of the indentation level, and prepend it to all inserted lines?
    if (/(\t*)#&#(\w+)/) { my $indent = length($1); apply_template($2, $indent); }
    Or you could run it all through W3C tidy at the end. :)

    If you use File::Find (and you should), have a look at $File::Find::dir, or $File::Find::name. If you then use File::Spec (and you should), you can turn an absolute path into a relative path -- relative to the root directory under which you're recursing.

    That all said, I definitely recommend picking up the Template Toolkit. You'll learn a lot rolling your own, but you'll probably paint yourself into a corner.

Re: Creating A Custom Markup
by perrin (Chancellor) on Dec 16, 2001 at 00:46 UTC
    I suggest you just post-process the output with HTML::PrettyPrinter. I also suggest you switch to Template Toolkit and ttree.
Re: Creating A Custom Markup
by Juerd (Abbot) on Dec 16, 2001 at 00:48 UTC
    You could of course rebuild the document using HTML::Parser...

    Or...
    sub do_file($$){ my ($file, $indent) = @_; local *FOO; open(FOO, $file); while (<FOO>) { /^(\t+)#&#(.+)/ && $indent = do_file($2, $indent + length $1); print; } close FOO; return $indent; }
    I've not tested it, and I'm not really sure what you want, but if this is what you were thinking of, you should recognize it :)
Re: Creating A Custom Markup
by Apoc (Initiate) on Dec 17, 2001 at 06:25 UTC
    In order to finish the thread, this is what I ended up using for a solution (improvments are very welcome):

    code:
    #!/usr/bin/perl -w
    
    use strict;
    use Template;
    use File::Copy;
    use File::Basename;
    
    
    #------------------------------------------------------------------------
    # config
    #------------------------------------------------------------------------
    
    #directory where your library files are located (files to be imported)
    my $libdir   = "d:\\files\\cu\\snippits";
    
    #directory that is to be searched (source files)
    my $srcdir   = "d:\\files\\cu\\html";
    
    #destination directory
    my $destdir  = "d:\\files\\html";
    
    #files that should be directly copied instead of processed
    my @copy     = ("\.png","\.gif","\.jpg","\.cgi");
    
    #------------------------------------------------------------------------
    # end config
    #------------------------------------------------------------------------
    
    my $ttopts   = {
        RELATIVE     => 1,
        INCLUDE_PATH => [ $srcdir, $libdir ],
        OUTPUT_PATH  => $destdir,
    };
    
    my $template = Template->new($ttopts);
    
    process_tree();
    
    sub process_tree {
        my $dir = shift;
        my ($file, $path, $abspath, $check);
        my $target;
        local *DIR;
    
        my $absdir = join('/', $srcdir ? $srcdir : (), $dir ? $dir : ());
        $absdir ||= '.';
    
        opendir(DIR, $absdir) || do { warn "$absdir: $!\n"; return undef; };
    
        FILE: while (defined ($file = readdir(DIR))) {
       next if $file eq '.' || $file eq '..';
       $path = $dir ? "$dir/$file" : $file;
       $abspath = "$absdir/$file";
       
       next unless -e $abspath;
    
       if (-d $abspath) {
          my ($uid, $gid, $mode);
    
          (undef, undef, $mode, undef, $uid, $gid, undef, undef,
           undef, undef, undef, undef, undef)  = stat($abspath);
    
          $target = "$destdir/$path";
          mkdir $target, $mode || do { warn "mkdir  ($target): $!\n"; next; };
          
          process_tree($path);
    
       }
       else {
           process_file($path, $abspath);
       }
        }
        closedir(DIR);
    }
    
    sub process_file {
        my ($file, $absfile) = @_;
        my ($dest, $base, $check, $srctime, $desttime, $mode, $uid, $gid);
    
        $absfile ||= $file;
        $dest = $destdir ? "$destdir/$file" : $file;
        $base = basename($file);
                    
        (undef, undef, $mode, undef, $uid, $gid, undef, undef, undef, $srctime,
         undef, undef, undef)  = stat($absfile);
        
        foreach $check (@copy) {
       if ($base =~ /$check/) {
    
          copy($absfile, $dest);
           return;
       }
        }
            $template->process($file, "", $file) || print("  ! ", $template->error(), "\n");
    }


    sample source file:
    [% depth="../../" %]
    
    <html>
       [% INCLUDE header title="Collectively Unconcious" %]
       [% INCLUDE open_body %]
          [% INCLUDE open_left_column %]
             [% INCLUDE site_menu %]
             [% INCLUDE cu_news %]
             [% INCLUDE search %]
          [% INCLUDE close_left_column %]
          [% INCLUDE open_middle_column %]
             [% INCLUDE who_are_we %]
                <!-- comment -->
                <table border="0" cellspacing="0" cellpadding="1" width="100%">
                   <tr>
                      <td background="[% depth %]images/border.gif" bgcolor="#000000">
                         <table bgcolor="#000000" width="100%" border="0" cellspacing="0" cellpadding="2" colspan=3>
                            <tr>
                               <td bgcolor="#9C0801" align="center" valign=middle><font size="2" class="nf"><b>What are we not?</b></font></td>
                            </tr>
                            <tr height="1">
                               <td bgcolor="CC3311"></td>
                            </tr>
                            <tr>
                               <td bgcolor="#191919">
                                  <b>Text goes here.<br><br>
                               </td>
                            </tr>
                         </table>
                      </td>
                   </tr>
                </table><br>
                <!-- /comment-->
          [% INCLUDE close_middle_column %]
          [% INCLUDE open_right_column %]
             [% INCLUDE cu_members %]
             [% INCLUDE your_account %]
             [% INCLUDE contribute %]
             [% INCLUDE book_review %]
          [% INCLUDE close_right_column %]
       [% INCLUDE close_body %]
    </html>


    sample INCLUDE (header)
    <head>
       <title>[% title %]</title>
       <script language="JavaScript">
          <!-- Begin popUp
             function popUp(URL) {
             day = new Date();
             id = day.getTime();
             eval("page" + id + " = window.open(URL, '" + id + "', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=525,left = 262,top = 134');");
             }
          // End  popUp-->
       </script>
    </head>