Toc(3)

πŸ“¦
version 1.12 Β· 2 versions
, in fedora 43

πŸ’– Toc(3) β€” HTML::Toc πŸ’–

okay bestie, buckle up β€” this is the HTML::Toc page from the User Contributed Perl Documentation, and it's a whole ✨situation✨. Grab a snack, we're doing this in parts. πŸ“


🌈 NAME 🌈

HTML::Toc β€” Generate, insert and update HTML Table of Contents. that's the whole job description fr fr πŸ’…


πŸ¦‹ DESCRIPTION πŸ¦‹

Generate, insert and update HTML Table of Contents (ToC). three verbs, one module family, endless vibes.

🌸 Introduction 🌸

So HTML::Toc is actually a little friend group 🫢 β€” it's made up of these packages:

HTML::Toc
HTML::TocGenerator
HTML::TocInsertor
HTML::TocUpdator

Let's do a roll call, because everyone has main character energy in their own lane:

  • HTML::Toc β€” the object that will eventually hold the Table of Contents. it's literally just the container. the handbag. πŸŽ€
  • HTML::TocGenerator β€” does the actual generation of the ToC. the one doing the work.
  • HTML::TocInsertor β€” handles the insertion of the ToC in the source.
  • HTML::TocUpdator β€” takes care of updating previously inserted ToCs.

HTML::Parser is the base object of HTML::TocGenerator, HTML::TocInsertor and HTML::TocUpdator. Each of these objects uses its predecessor as its ancestor, as shown in the UML diagram underneath:

    +---------------------+
    |    HTML::Parser     |
    +---------------------+
    +---------------------+
    |    +parse()         |
    |    +parse_file()    |
    +----------+----------+
              /_\
               |
    +----------+----------+  <<uses>>  +-----------+
    | HTML::TocGenerator  + - - - - - -+ HTML::Toc |
    +---------------------+            +-----------+
    +---------------------+            +-----------+
    | +extend()           |            | +clear()  |
    | +extendFromFile()   |            | +format() |
    | +generate()         |            +-----+-----+
    | +generateFromFile() |                  :
    +----------+----------+                  :
              /_\                            :
               |                             :
    +----------+----------+     <<uses>>     :
    |  HTML::TocInsertor  + - - - - - - - - -+
    +---------------------+                  :
    +---------------------+                  :
    |  +insert()          |                  :
    |  +insertIntoFile()  |                  :
    +----------+----------+                  :
              /_\                            :
               |                             :
    +----------+----------+     <<uses>>     :
    |  HTML::TocUpdator   + - - - - - - - - -+
    +---------------------+
    +---------------------+
    |  +insert()          |
    |  +insertIntoFile()  |
    |  +update()          |
    |  +updateFile()      |
    +---------------------+

vibe check: when generating a ToC you'll have to decide which object you want to use:

  • TocGenerator: for generating a ToC without inserting the ToC into the source
  • TocInsertor: for generating a ToC and inserting the ToC into the source
  • TocUpdator: for generating and inserting a ToC, removing any previously inserted ToC elements

Thus in tabular view, each object is capable of: (look at them, so capable πŸ₯Ή)

                   generating   inserting   updating
                   ---------------------------------
TocGenerator        X
TocInsertor         X           X
TocUpdator          X           X           X

✨ Generating ✨

The code underneath will generate a ToC of the HTML headings "<h1">.."<h6"> from a file "index.htm":

use HTML::Toc;
use HTML::TocGenerator;

my $toc          = HTML::Toc->new();
my $tocGenerator = HTML::TocGenerator->new();

$tocGenerator->generateFromFile($toc, 'index.htm');
print $toc->format();

For example, with "index.htm" containing:

<html>
<body>
   <h1>Chapter</h1>
</body>
</html>

the output will be:

<!-- Table of Contents generated by Perl - HTML::Toc -->
<ul>
<li><a href="#h-1">Chapter</a></li>
</ul>
<!-- End of generated Table of Contents -->

ate and left no crumbs. πŸ’…

πŸŽ€ Inserting πŸŽ€

This code will generate a ToC of HTML headings "<h1">.."<h6"> of file "index.htm", and insert the ToC after the "<body"> tag at the same time:

use HTML::Toc;
use HTML::TocInsertor;

my $toc         = HTML::Toc->new();
my $tocInsertor = HTML::TocInsertor->new();

$tocInsertor->insertIntoFile($toc, 'index.htm');

For example, with "index.htm" containing:

<html>
<body>
   <h1>Chapter</h1>
</body>
</html>

the output will be:

<html>
<body>
<!-- Table of Contents generated by Perl - HTML::Toc -->
<ul>
<li><a href="#h-1">Chapter</a></li>
</ul>
<!-- End of generated Table of Contents -->

<h1><a name="h-1"></a>Chapter</h1>
</body>
</html>

🌟 Inserting into string 🌟

By default, HTML::TocInsertor::insert() prints both the string and the generated ToC to standard output. To actually insert the ToC in the string, use the output option to specify a scalar reference to insert the ToC into:

use HTML::Toc;
use HTML::TocInsertor;

my $toc         = HTML::Toc->new();
my $tocInsertor = HTML::TocInsertor->new();

$html =<<HTML;
<html>
<body>
   <h1>Chapter</h1>
</body>
</html>
HTML
$tocInsertor->insert($toc, $html, {'output' => \$html});
print $html;

Now the output will be:

<html>
<body>
<!-- Table of Contents generated by Perl - HTML::Toc -->
<ul>
   <li><a href="#h-1">Chapter</a></li>
</ul>
<!-- End of generated Table of Contents -->

   <h1><a name="h-1"></a>Chapter</h1>
</body>
</html>

scalar reference my beloved 🫢

🌟 Inserting with update tokens 🌟

If you're planning to update the inserted ToC, you'd better use "TocUpdator" to insert the ToC. "TocUpdator" marks the inserted ToC elements with update tokens. These update tokens allow "TocUpdator" to identify and remove the ToC elements during a future update session. This code uses "TocUpdator" instead of "TocInsertor":

use HTML::Toc;
use HTML::TocUpdator;

my $toc        = HTML::Toc->new();
my $tocUpdator = HTML::TocUpdator->new();

$tocUpdator->insertIntoFile($toc, 'index.htm');

When applying the code above on 'index.htm':

<html>
<body>
   <h1>
   Chapter
   </h1>
</body>
</html>

the output will contain additional update tokens:

<!-- #BeginToc -->
<!-- #EndToc -->
<!-- #BeginTocAnchorNameBegin -->
<!-- #EndTocAnchorNameBegin -->
<!-- #BeginTocAnchorNameEnd -->
<!-- #EndTocAnchorNameEnd -->

around the inserted ToC elements:

<html>
<body><!-- #BeginToc -->
<!-- Table of Contents generated by Perl - HTML::Toc -->
<ul>
   <li><a href="#h-1"> Chapter </a></li>
</ul>
<!-- End of generated Table of Contents -->
<!-- #EndToc -->
   <h1><!-- #BeginTocAnchorNameBegin --><a name="h-1"></a><!-- #EndTocAnchorNameBegin -->
   Chapter
   </h1>
</body>
</html>

Instead of "HTML::TocUpdator::insertIntoFile" you can also use HTML::TocUpdator::updateFile(). HTML::TocUpdator::updateFile() will also insert the ToC, whether there is a ToC already inserted or not. it's giving overachiever, and we love that for it. ✨

πŸ’œ Updating πŸ’œ

This code will generate a ToC of HTML headings "<h1">.."<h6"> of file "indexToc.htm", and insert or update the ToC after the "<body"> tag at the same time:

use HTML::Toc;
use HTML::TocUpdator;

my $toc        = HTML::Toc->new();
my $tocUpdator = HTML::TocUpdator->new();

$tocUpdator->updateFile($toc, 'indexToc.htm');

For example, with "indexToc.htm" containing:

<html>
<body><!-- #BeginToc -->
foo
<!-- #EndToc -->
   <!-- #BeginTocAnchorNameBegin -->bar<!-- #EndTocAnchorNameBegin --><h1>
   Chapter
   </h1><!-- #BeginTocAnchorNameEnd -->foo<!-- #EndTocAnchorNameEnd -->
</body>h
</html>

the output will be:

<html>
<body><!-- #BeginToc -->
<!-- Table of Contents generated by Perl - HTML::Toc -->
<ul>
   <li><a href="#h-1"> Chapter </a></li>
</ul>
<!-- End of generated Table of Contents -->
<!-- #EndToc -->
   <h1><!-- #BeginTocAnchorNameBegin --><a name="h-1"></a><!-- #EndTocAnchorNameBegin -->
   Chapter
   </h1>
</body>
</html>

All text between the update tokens will be replaced. So be warned: all manual changes made to text between update tokens will be removed unrecoverable after calling HTML::TocUpdator::update() or HTML::TocUpdator::updateFile().

⚠️ BESTIE. LISTEN. ⚠️ everything you hand-edited between those update tokens? gone. unrecoverable. no undo, no take-backs, no "wait I didn't mean to". πŸ’€ back up your stuff before you call HTML::TocUpdator::update() or HTML::TocUpdator::updateFile().

🧚 Formatting 🧚

The ToC isn't generated all at once. There are two stages involved: generating and formatting. Generating the ToC actually means storing a preliminary ToC in "HTML::Toc->{_toc}". This preliminary, tokenized ToC has to be turned into something useful by calling "HTML::Toc->format()". For an example, see paragraph 'Generating'.

two-step process, like getting ready. first you exist, then you format. πŸ’…


πŸ‘‘ Advanced πŸ‘‘

The ToC generation can be modified in a variety of ways. The following paragraphs each explain a single modification. An example of most of the modifications can be found in the "manualTest.t" test file. Within this test, a manual containing:

preface
introduction
table of contents
table of figures
table of tables
parts
chapters
appendixes
bibliography

is formatted all at once. all at once!! no cap!! πŸ”₯

πŸ¦‹ Using attribute value as ToC text πŸ¦‹

Normally, the ToC will be made of text between specified ToC tokens. It's also possible to use the attribute value of a token as a ToC text. This can be done by specifying the attribute marked with an attributeToTocToken within the tokenBegin token. For example, suppose you want to generate a ToC of the "alt" attributes of the following image tokens:

<body>
   <img src=test1.gif alt="First picture">
   <img src=test2.gif alt="Second picture">
</body>

This would be the code:

use HTML::Toc;
use HTML::TocInsertor;

my $toc         = HTML::Toc->new();
my $tocInsertor = HTML::TocInsertor->new();

$toc->setOptions({
   'tokenToToc'   => [{
      'groupId'    => 'image',
      'tokenBegin' => '<img alt=@>'
   }],
});
$tocInsertor->insertIntoFile($toc, $filename);

and the output will be:

<body>
<!-- Table of Contents generated by Perl - HTML::Toc -->
<ul>
   <li><a href="#image-1">First picture</a></li>
   <li><a href="#image-2">Second picture</a></li>
</ul>
<!-- End of generated Table of Contents -->

   <a name="image-1"></a><img src="test1.gif" alt="First picture">
   <a name="image-2"></a><img src="test2.gif" alt="Second picture">
</body>

the @ is doing so much heavy lifting here and it's iconic ⭐

🌈 Generating a single ToC from multiple files

Okay so here's the tea bestie β˜• β€” you're not limited to one file! You can make one ToC that spans several files, and there are two ways to do it: hand it an array of files as the file argument, and/or extend a ToC you already built. Both work, and they even play nice together πŸ’…

✨ Specify an array of files

Say you wanna make a ToC covering both doc1.htm:

<body>
   <h1>Chapter of document 1</h1>
</body>

and doc2.htm:

<body>
   <h1>Chapter of document 2</h1>
</body>

Here's the code that does the thing by passing an array of files:

use HTML::Toc;
use HTML::TocGenerator;

my $toc          = HTML::Toc->new();
my $tocGenerator = HTML::TocGenerator->new();

$toc->setOptions({'doLinkToFile' => 1});
$tocGenerator->generateFromFile($toc, ['doc1.htm', 'doc2.htm']);
print $toc->format();

And the output will be:

<!-- Table of Contents generated by Perl - HTML::Toc -->
<ul>
   <li><a href="doc1.htm#h-1">Chapter of document 1</a></li>
   <li><a href="doc2.htm#h-2">Chapter of document 2</a></li>
</ul>
<!-- End of generated Table of Contents -->

✨ Extend an existing ToC

You can also extend a ToC you've already made. Say we generate a ToC from doc1.htm:

<body>
   <h1>Chapter of document 1</h1>
</body>

and then extend it with the content of doc2.htm:

<body>
   <h1>Chapter of document 2</h1>
</body>

Here's the code:

use HTML::Toc;
use HTML::TocGenerator;

my $toc          = HTML::Toc->new();
my $tocGenerator = HTML::TocGenerator->new();

$toc->setOptions({'doLinkToFile' => 1});
$tocGenerator->generateFromFile($toc, 'doc1.htm');
$tocGenerator->extendFromFile($toc, 'doc2.htm');
print $toc->format();

And the output will be:

<!-- Table of Contents generated by Perl - HTML::Toc -->
<ul>
   <li><a href="doc1.htm#h-1">Chapter of document 1</a></li>
   <li><a href="doc2.htm#h-2">Chapter of document 2</a></li>
</ul>
<!-- End of generated Table of Contents -->

🌸 Generate multiple ToCs

Not me about to blow your mind 🀯 β€” you can generate several ToCs in one go by passing an array of HTML::Toc objects as the ToC argument. Say you want a default ToC of HTML headings h1..h6, plus a ToC of the alt image attributes of this text right here:

<body>
   <h1>Header One</h1>
   <img src="test1.gif" alt="First picture">
   <h2>Paragraph One</h2>
   <img src="test2.gif" alt="Second picture">
</body>

Here's how you do it:

use HTML::Toc;
use HTML::TocInsertor;

my $toc1        = HTML::Toc->new();
my $toc2        = HTML::Toc->new();
my $tocInsertor = HTML::TocInsertor->new();

$toc2->setOptions({
   'tokenToToc'   => [{
      'groupId'    => 'image',
      'tokenBegin' => '<img alt=@>'
   }],
});
$tocInsertor->insertIntoFile([$toc1, $toc2], $filename);

And the output will be:

<body>
<!-- Table of Contents generated by Perl - HTML::Toc -->
<ul>
   <li><a href="#h-1">Header One</a>
      <ul>
         <li><a href="#h-1.1">Paragraph One</a></li>
      </ul>
   </li>
</ul>
<!-- End of generated Table of Contents -->

<!-- Table of Contents generated by Perl - HTML::Toc -->
<ul>
   <li><a href="#image-1">First picture</a>
   <li><a href="#image-2">Second picture</a>
</ul>
<!-- End of generated Table of Contents -->

   <h1><a name="h-1"></a>Header One</h1>
   <a name="image-1"></a><img src="test1.gif" alt="First picture"/>
   <h2><a name="h-1.1"></a>Paragraph One</h2>
   <a name="image-2"></a><img src="test2.gif" alt="Second picture"/>
</body>

πŸ’œ Generate multiple groups in one ToC

Sometimes you want a ToC made of multiple ToC groups β€” like one group for the normal stuff and another for something else. Periodt πŸ’…

πŸŽ€ Specify an additional 'Appendix' group

Say you want a ToC with one group for the normal headings and one group for the appendix headings, using this source file:

<body>
   <h1>Chapter</h1>
   <h2>Paragraph</h2>
   <h3>Subparagraph</h3>
   <h1>Chapter</h1>
   <h1 class="appendix">Appendix Chapter</h1>
   <h2 class="appendix">Appendix Paragraph</h2>
</body>

With the code underneath:

use HTML::Toc;
use HTML::TocInsertor;

my $toc         = HTML::Toc->new();
my $tocInsertor = HTML::TocInsertor->new();

$toc->setOptions({
   'tokenToToc' => [{
         'tokenBegin' => '<h1 class="-appendix">'
      }, {
         'tokenBegin' => '<h2 class="-appendix">',
         'level'      => 2
      }, {
         'groupId'    => 'appendix',
         'tokenBegin' => '<h1 class="appendix">',
      }, {
         'groupId'    => 'appendix',
         'tokenBegin' => '<h2 class="appendix">',
         'level'      => 2
      }]
});
$tocInsertor->insertIntoFile($toc, $filename);

the output will be:

<body>
<!-- Table of Contents generated by Perl - HTML::Toc -->
<ul>
   <li><a href="#h-1">Chapter</a>
      <ul>
         <li><a href="#h-1.1">Paragraph</a></li>
      </ul>
   </li>
   <li><a href="#h-2">Chapter</a></li>
</ul>
<ul>
   <li><a href="#appendix-1">Appendix Chapter</a>
      <ul>
         <li><a href="#appendix-1.1">Appendix Paragraph</a></li>
      </ul>
   </li>
</ul>
<!-- End of generated Table of Contents -->

   <h1><a name="h-1"></a>Chapter</h1>
   <h2><a name="h-1.1"></a>Paragraph</h2>
   <h3>Subparagraph</h3>
   <h1><a name="h-2"></a>Chapter</h1>
   <h1 class="appendix"><a name="appendix-1"></a>Appendix Chapter</h1>
   <h2 class="appendix"><a name="appendix-1.1"></a>Appendix Paragraph</h2>
</body>

πŸŽ€ Specify an additional 'Part' group

Now say you want a ToC of a document that's split into multiple parts, like this file right here:

<body>
   <h1 class="part">First Part</h1>
   <h1>Chapter</h1>
   <h2>Paragraph</h2>
   <h1 class="part">Second Part</h1>
   <h1>Chapter</h1>
   <h2>Paragraph</h2>
</body>

With the code underneath:

use HTML::Toc;
use HTML::TocInsertor;

my $toc         = HTML::Toc->new();
my $tocInsertor = HTML::TocInsertor->new();

$toc->setOptions({
   'doNumberToken'    => 1,
   'tokenToToc' => [{
         'tokenBegin' => '<h1 class="-part">'
      }, {
         'tokenBegin' => '<h2 class="-part">',
         'level'      => 2,
      }, {
         'groupId'        => 'part',
         'tokenBegin'     => '<h1 class="part">',
         'level'          => 1,
         'doNumberToken'  => 1,
         'numberingStyle' => 'upper-alpha'
      }]
});
$tocInsertor->insertIntoFile($toc, $filename);

the output will be:

<body>
<!-- Table of Contents generated by Perl - HTML::Toc -->
<ul>
   <li><a href="#part-A">First Part</a></li>
</ul>
<ul>
   <li><a href="#h-1">Chapter</a>
      <ul>
         <li><a href="#h-1.1">Paragraph</a></li>
      </ul>
   </li>
</ul>
<ul>
   <li><a href="#part-B">Second Part</a></li>
</ul>
<ul>
   <li><a href="#h-2">Chapter</a>
      <ul>
         <li><a href="#h-2.1">Paragraph</a></li>
      </ul>
   </li>
</ul>
<!-- End of generated Table of Contents -->

   <h1 class="part"><a name="part-A"></a>A &nbsp;First Part</h1>
   <h1><a name="h-1"></a>Chapter</h1>
   <h2><a name="h-1.1"></a>Paragraph</h2>
   <h1 class="part"><a name="part-B"></a>B &nbsp;Second Part</h1>
   <h1><a name="h-2"></a>Chapter</h1>
   <h2><a name="h-2.1"></a>Paragraph</h2>
</body>

πŸ‘‘ Number ToC entries

By default the generated ToC lists its entries unnumbered. But bestie, if you want numbers, you got two options on the menu πŸ“ β€” either you specify a numbered list by tweaking templateLevelBegin and templateLevelEnd, or (when your ToC isn't a simple numbered list) you use the numbers generated by HTML::TocGenerator.

⭐ Specify numbered list

Tweak templateLevelBegin and templateLevelEnd and boom, numbered ToC:

use HTML::Toc;
use HTML::TocGenerator;

my $toc          = HTML::Toc->new();
my $tocGenerator = HTML::TocGenerator->new();

$toc->setOptions({
    'templateLevelBegin' => '"<ol>\n"',
    'templateLevelEnd'   => '"</ol>\n"',
});
$tocGenerator->generateFromFile($toc, 'index.htm');
print $toc->format();

So like, if your original file has:

<body>
    <h1>Chapter</h1>
    <h2>Paragraph</h2>
</body>

The formatted ToC now will contain "ol" instead of "ul" tags:

<!-- Table of Contents generated by Perl - HTML::Toc -->
<ol>
   <li><a href="#h-1">Chapter</a>
      <ol>
         <li><a href="#h-1.1">Paragraph</a></li>
      </ol>
   </li>
</ol>
<!-- End of generated Table of Contents -->

See also: Using CSS for ToC formatting.

⭐ Use generated numbers

Instead of using the HTML ordered list (OL), it's also possible to use the generated numbers to number to ToC nodes 🧚. You do that by modifying templateLevel:

use HTML::Toc;
use HTML::TocGenerator;

my $toc          = HTML::Toc->new();
my $tocGenerator = HTML::TocGenerator->new();

$toc->setOptions({
   'templateLevel' => '"<li>$node &nbsp;$text"',
});
$tocGenerator->generateFromFile($toc, 'index.htm');
print $toc->format();

So like, if your original file has:

<body>
    <h1>Chapter</h1>
    <h2>Paragraph</h2>
</body>

The formatted ToC now will have the node numbers hard-coded:

<!-- Table of Contents generated by Perl - HTML::Toc -->
<ul>
   <li>1 &nbsp;<a href=#h-1>Chapter</a>
      <ul>
         <li>1.1 &nbsp;<a href=#h-1.1>Paragraph</a></li>
      </ul>
   </li>
</ul>
<!-- End of generated Table of Contents -->

See also: Using CSS for ToC formatting β€” yeah bestie that's literally the next bit, keep reading πŸ’–


Using CSS for ToC formatting πŸŽ€

Okay so picture this: you want your ToC to show appendix headings numbered with upper-alpha (A, B, C… the cute ones). The move is to drop a CSS style right into the source document, like so:

<html>
<head>
   <style type="text/css">
      ol.toc_appendix1 { list-style-type: upper-alpha }
   </style>
</head>
<body>
   <h1>Appendix</h1>
   <h2>Appendix Paragraph</h2>
   <h1>Appendix</h1>
   <h2>Appendix Paragraph</h2>
</body>
</html>

And here's the code that does the thing ✨

my $toc          = new HTML::Toc;
my $tocInsertor  = new HTML::TocInsertor;

$toc->setOptions({
   'templateLevelBegin'   => '"<ol class=toc_$groupId$level>\n"',
   'templateLevelEnd'     => '"</ol>\n"',
   'doNumberToken'        => 1,
   'tokenToToc' => [{
         'groupId'        => 'appendix',
         'tokenBegin'     => '<h1>',
         'numberingStyle' => 'upper-alpha'
      }, {
         'groupId'        => 'appendix',
         'tokenBegin'     => '<h2>',
         'level'          => 2,
     }]
});
$tocInsertor->insertIntoFile($toc, $filename);

Which gives you this absolute serve as output:

<html>
<head>
   <style type="text/css">
      ol.toc_appendix1 { list-style-type: upper-alpha }
   </style>
</head>
<body>
<!-- Table of Contents generated by Perl - HTML::Toc -->
<ol class="toc_appendix1">
   <li><a href="#appendix-A">Appendix</a>
      <ol class="toc_appendix2">
         <li><a href="#appendix-A.1">Appendix Paragraph</a></li>
      </ol>
   </li>
   <li><a href="#appendix-B">Appendix</a>
      <ol class="toc_appendix2">
         <li><a href="#appendix-B.1">Appendix Paragraph</a></li>
      </ol>
   </li>
</ol>
<!-- End of generated Table of Contents -->

   <h1><a name="appendix-A"></a>A &nbsp;Appendix</h1>
   <h2><a name="appendix-A.1"></a>A.1 &nbsp;Appendix Paragraph</h2>
   <h1><a name="appendix-B"></a>B &nbsp;Appendix</h1>
   <h2><a name="appendix-B.1"></a>B.1 &nbsp;Appendix Paragraph</h2>
</body>
</html>

Slay. Look at those <ol class="toc_appendix1"> classes doing exactly what the CSS said. Obsessed. πŸ’…


Creating site map πŸ¦‹

Now this one is so fun. Say you wanna build a table of contents out of the <title> tags of every file in a directory tree that looks like this:

path               file

.                  index.htm, <title>Main</title>
|- SubDir1         index.htm, <title>Sub1</title>
|  |- SubSubDir1   index.htm, <title>SubSub1</title>
|
|- SubDir2         index.htm, <title>Sub2</title>
|  |- SubSubDir1   index.htm, <title>SubSub1</title>
|  |- SubSubDir2   index.htm, <title>SubSub2</title>
|
|- SubDir3         index.htm, <title>Sub3</title>

The trick is 'fileSpec' β€” it decides how many slashes (/) a file is allowed to have for each specific level. Like a little vibe check for depth 🌈

use HTML::Toc;
use HTML::TocGenerator;
use File::Find;

my $toc          = HTML::Toc->new;
my $tocGenerator = HTML::TocGenerator->new;
my @fileList;

sub wanted {
      # Add file to 'fileList' if extension matches '.htm'
   push (@fileList, $File::Find::name) if (m/\.htm$/);
}

$toc->setOptions({
   'doLinkToFile'       => 1,
   'templateAnchorName' => '""',
   'templateAnchorHref' => '"<a href=$file"."#".$groupId.$level.">"',
   'doLinkTocToToken'   => 1,
   'tokenToToc'         => [{
      'groupId'         => 'dir',
      'level'           => 1,
      'tokenBegin'      => '<title>',
      'tokenEnd'        => '</title>',
      'fileSpec'        => '\./[^/]+$'
   }, {
      'groupId'         => 'dir',
      'level'           => 2,
      'tokenBegin'      => '<title>',
      'tokenEnd'        => '</title>',
      'fileSpec'        => '\./[^/]+?/[^/]+$'
   }, {
      'groupId'         => 'dir',
      'level'           => 3,
      'tokenBegin'      => '<title>',
      'tokenEnd'        => '</title>',
      'fileSpec'        => '\./[^/]+?/[^/]+?/[^/]+$'
   }]
});

   # Traverse directory structure
find({wanted => \&wanted, no_chdir => 1}, '.');
   # Generate ToC of case-insensitively sorted file list
$tocGenerator->extendFromFile(
   $toc, [sort {uc($a) cmp uc($b)} @fileList]
);
print $toc->format();

And boom, this ToC gets generated πŸŽ‰:

<!-- Table of Contents generated by Perl - HTML::Toc -->
<ul>
   <li><a href="./index.htm#">Main</a>
      <ul>
         <li><a href="./SubDir1/index.htm#">Sub1</a>
            <ul>
               <li><a href="./SubDir1/SubSubDir1/index.htm#">SubSub1</a></li>
            </ul>
         </li>
         <li><a href="./SubDir2/index.htm#">Sub2</a>
            <ul>
               <li><a href="./SubDir2/SubSubDir1/index.htm#">SubSub1</a></li>
               <li><a href="./SubDir2/SubSubDir2/index.htm#">SubSub2</a></li>
            </ul>
         </li>
         <li><a href="./SubDir3/index.htm#">Sub3</a></li>
      </ul>
   </li>
</ul>
<!-- End of generated Table of Contents -->

Nested <ul>s going three levels deep, sort {uc($a) cmp uc($b)} making it case-insensitive, the whole thing just working. Iconic behaviour, no cap. ✨


Methods πŸ‘‘

HTML::Toc::clear()

  • syntax: $toc->clear()
  • returns: --

Clears the ToC. That's it, that's the whole job. Wipes it clean 🧼

HTML::Toc::format()

  • syntax: $scalar = $toc->format()
  • returns: Formatted ToC.

Formats the tokenized ToC. You feed it tokens, it hands you back the pretty version πŸ’–

HTML::TocGenerator::extend()

  • syntax: $tocGenerator->extend($toc, $string [, $options])
  • args:
    • $toc: (reference to array of) HTML::Toc object(s) to extend
    • $string: string to retrieve ToC from
    • $options: hash reference containing generator options.

Extends a ToC from the string you give it. Wanna know what options you can pass? Go look at Parser Options 🫢

HTML::TocGenerator::extendFromFile()

  • syntax: $tocGenerator->extendFromFile($toc, $filename [, $options])
  • args:
    • $toc: (reference to array of) HTML::Toc object(s) to extend
    • $filename: (reference to array of) file(s) to extend ToC from
    • $options: hash reference containing generator options.

Extends a ToC from a file instead. Options? Again, Parser Options. And if you want a whole example, go peek at "Extend an existing ToC" πŸ“

HTML::TocGenerator::generate()

  • syntax: $tocGenerator->generate($toc, $string [, $options])
  • args:
    • $toc: (reference to array of) HTML::Toc object(s) to generate
    • $string: string to retrieve ToC from
    • $options: hash reference containing generator options.

Generates a ToC from the string you hand over. Heads up though β€” before it generates, the ToC gets cleared first 😭 so if you wanted to add onto an existing ToC, use HTML::TocGenerator::extend() instead. Options live in Parser Options.

HTML::TocGenerator::generateFromFile()

  • syntax: $tocGenerator->generateFromFile($toc, $filename [, $options])
  • args:
    • $toc: (reference to array of) HTML::Toc object(s) to generate
    • $filename: (reference to array of) file(s) to generate ToC from
    • $options: hash reference containing generator options.

Generates a ToC from a file. Same deal: the ToC gets cleared before generating, so if you're extending an existing one, you want HTML::TocGenerator::extendFromFile() instead. Options β†’ Parser Options.

HTML::TocInsertor::insert()

  • syntax: $tocInsertor->insert($toc, $string [, $options])
  • args:
    • $toc: (reference to array of) HTML::Toc object(s) to insert
    • $string: string to insert ToC in
    • $options: hash reference containing insertor options.

Generates a ToC from the string you give it. The string and the generated ToC both get printed to standard output. Options β†’ Parser Options.

NOTE: If you actually want the ToC inserted into the string (not just printed), you gotta use the output option and hand it a scalar reference to insert into. There's an example in Insert into string πŸ’‘

HTML::TocInsertor::insertIntoFile()

  • syntax: $tocInsertor->insertIntoFile($toc, $filename [, $options])
  • args:
    • $toc: (reference to array of) HTML::Toc object(s) to insert
    • $filename: (reference to array of) file(s) to insert ToC in
    • $options: hash reference containing insertor options.

Inserts the ToC into the file you specify. Options β†’ Parser Options.

HTML::TocUpdator::insert()

  • syntax: $tocUpdator->insert($toc, $string [, $options])
  • args:
    • $toc: (reference to array of) HTML::Toc object(s) to insert
    • $string: string to insert ToC in
    • $options: hash reference containing updator options.

Inserts a ToC into the string you give it. How's it different from HTML::TocInsertor::insert()? Glad you asked bestie β€” the inserted text gets wrapped in update tokens, so that "HTML::TocUpdator" can come back and update that text the next time an update is issued πŸ”₯ See also: Update options.

HTML::TocUpdator::insertIntoFile()

  • syntax: $tocUpdator->insertIntoFile($toc, $filename [, $options])
  • args:
    • $toc: (reference to array of) HTML::Toc object(s) to insert
    • $filename: (reference to array of) file(s) to insert ToC in
    • $options: hash reference containing updator options.

Inserts a ToC into the file you name. Same difference as above: the inserted text gets surrounded with update tokens, so "HTML::TocUpdator" can update it later. Updator options β†’ Update options πŸ’œ

HTML::TocUpdator::update()

  • syntax: $tocUpdator->update($toc, $string [, $options])
  • args:
    • $toc: (reference to array of) HTML::Toc object(s) to insert
    • $string: string to update ToC in
    • $options: hash reference containing updator options.

Updates the ToC inside the string you give it. Updator options β†’ Update options.

HTML::TocUpdator::updateFile()

  • syntax: $tocUpdator->updateFile($toc, $filename [, $options])
  • args:
    • $toc: (reference to array of) HTML::Toc object(s) to insert
    • $filename: (reference to array of) file(s) to update ToC in
    • $options: hash reference containing updator options.

Updates the ToC of the file you name. Updator options β†’ Update options.


✨ Parser Options ✨

okay so when you're generating a ToC, you can hand over extra options that literally change how the ToC gets made β€” and you can do this whether you're rolling with TocGenerator, TocInsertor or TocUpdator. Bestie, these options must be given as a hash reference. Like, for real, hash ref or nothing. Example:

$tocGenerator->generateFromFile($toc, $filename, {doUseGroupsGlobal => 1});

Here's the full menu of what you can pass:

  • doGenerateToc
  • doUseGroupsGlobal
  • output
  • outputFile

doGenerateToc πŸ’«

syntax:         [0|1]
default:        1
applicable to:  TocInsertor, TocUpdator

True (1) means the ToC must be generated. False (0) means the ToC only gets inserted, no generation happening. πŸ’…


doUseGroupsGlobal πŸŒ€

syntax:         [0|1]
default:        0
applicable to:  TocGenerator, TocInsertor, TocUpdator

True (1) = group levels are used globally across ToCs. False (0) = they're not, each one stays in its lane. This option only makes sense when you've specified an array of ToCs, iykyk.

Say you wanna generate two ToCs from the file index.htm β€” one for 'h1' tokens and one for 'h2' tokens:

<h1>Chapter</h1>
<h2>Paragraph</h2>

With the default setting of 'doUseGroupsGlobal' => 0:

use HTML::Toc;
use HTML::TocGenerator;

my $toc1         = HTML::Toc->new();
my $toc2         = HTML::Toc->new();
my $tocGenerator = HTML::TocGenerator->new();

$toc1->setOptions({
   'header'     => '',
   'footer'     => '',
   'tokenToToc' => [{'tokenBegin' => '<h1>'}]
});
$toc2->setOptions({
   'header'     => '',
   'footer'     => '',
   'tokenToToc' => [{'tokenBegin' => '<h2>'}]
});
$tocGenerator->generateFromFile([$toc1, $toc2], 'index.htm');
print $toc1->format() . "\n\n" . $toc2->format();

the output will be:

<ul>
   <li><a href=#h-1>Chapter</a>
</ul>

<ul>
   <li><a href=#h-1>Paragraph</a>
</ul>

Each ToC uses its own numbering scheme β€” they don't share, they don't compare, they're independent queens. πŸ‘‘

Now if "doUseGroupsGlobal = 1" is specified:

$tocGenerator->generateFromFile(
   [$toc1, $toc2], 'index.htm', {'doUseGroupsGlobal' => 1}
);

the output will be:

<ul>
   <li><a href=#h-1>Chapter</a>
</ul>

<ul>
   <li><a href=#h-2>Paragraph</a>
</ul>

using a global numbering scheme for all ToCs. Slay. ✨


output πŸ“€

syntax:         reference to scalar
default:        none
applicable to:  TocInsertor, TocUpdator

A reference to a scalar, which is where the output must be stored. That's it, that's the whole vibe.


outputFile πŸ“

syntax:         scalar
default:        none
applicable to:  TocInsertor, TocUpdator

The filename to write output to. If no filename is specified, output will be written to standard output. Default behaviour, no drama. 🫢


πŸ’– HTML::Toc Options πŸ’–

The HTML::Toc options can be grouped into these categories:

  • Generate options
  • Insert options
  • Update options
  • Format options

The ToC options must be specified using the 'setOptions' method. For example:

my $toc = new HTML::Toc;

$toc->setOptions({
   'doNumberToken' => 1,
   'footer'        => '<!-- End Of ToC -->'
   'tokenToToc'    => [{
      'level'          => 1,
      'tokenBegin'     => '<h1>',
      'numberingStyle' => 'lower-alpha'
   }]
});

Generate options 🌱

  • Token groups
    • tokenToToc
      • doNumberToken
      • fileSpec
      • groupId
      • level
      • tokenBegin
      • tokenEnd
      • numberingStyle
    • groupToToc
    • levelToToc
  • Numbering tokens
    • doNumberToken
    • numberingStyle
    • templateTokenNumber
  • Miscellaneous
    • attributeToExcludeToken
    • attributeToTocToken
    • groupToToc
    • levelToToc
  • Linking ToC to tokens
    • doLinkToToken
    • doLinkToFile
    • doLinkToId
    • templateAnchorName
    • templateAnchorHrefBegin
    • templateAnchorHrefEnd
    • templateAnchorNameBegin
    • templateAnchorNameEnd

Insert options πŸͺ„

  • insertionPoint

Update options πŸ”„

  • tokenUpdateBeginAnchorName
  • tokenUpdateEndAnchorName
  • tokenUpdateBeginToc
  • tokenUpdateEndToc
  • tokenUpdateBeginNumber
  • tokenUpdateEndNumber

Format options πŸŽ€

  • doSingleStepLevel
  • doNestGroup
  • footer
  • groupToToc
  • header
  • levelIndent
  • levelToToc
  • templateLevel
  • templateLevelClose
  • templateLevelBegin
  • templateLevelEnd

πŸ‘‘ HTML::Toc Options Reference πŸ‘‘

attributeToExcludeToken 🚫

syntax:  $scalar
default: '-'

Token which marks an attribute value in a tokenBegin or insertionPoint token as an attribute value a token should not have to be marked as a ToC token. See also: Using attribute value as ToC entry.


attributeToTocToken πŸ’¬

syntax:  $scalar
default: '@'

Token which marks an attribute in a tokenBegin token as an attribute which must be used as ToC text. See also: Using attribute value as ToC entry.


doLinkToToken πŸ”—

syntax:  [0|1]
default: 1

True (1) if ToC must be linked to tokens, False (0) if not. Note that 'HTML::TocInsertor' must be used to do the actual insertion of the anchor name within the source data. So like, this flag says you want the link β€” but somebody else has to actually do the inserting, bestie. πŸ™ˆ


doLinkToFile πŸ“„

syntax:  [0|1]
default: 0

True (1) if ToC must be linked to file, False (0) if not. In effect only when doLinkToToken equals True (1) and templateAnchorHrefBegin isn't specified. Two conditions, both non-negotiable. πŸ’…


doLinkToId πŸ†”

syntax:  [0|1]
default: 0

True (1) if ToC must be linked to tokens by using token ids. False (0) if ToC must be linked to tokens by using anchor names. Pick your fighter. βš”οΈ


doNestGroup πŸͺΊ

syntax:  [0|1]
default: 0

True (1) if groups must be nested in the formatted ToC, False (0) if not. In effect only when multiple groups are specified within the tokenToToc setting. For an example, see Generate multiple groups in one ToC.


doNumberToken πŸ”’

syntax:  [0|1]
default: 0

True (1) if tokens which are used for the ToC generation must be numbered. This option may be specified both as a global ToC option or within a tokenToToc group. When specified within a "tokenToToc" option, the "doNumberToken" applies to that group only. For an example, see Specify an additional 'Part' group.


doSingleStepLevel πŸͺœ

syntax:  [0|1]
default: 1

True (1) if levels of a formatted ToC must advance one level at a time. For example, when generating a ToC of a file with a missing 'h2':

<h1>Chapter</h1>
<h3>Paragraph</h3>

By default, an empty indentation level will be inserted in the ToC:

<!-- Table of Contents generated by Perl - HTML::Toc -->
<ul>
   <li><a href=#h-1>Header 1</a>
   <ul>
      <ul>
         <li><a href=#h-1.0.1>Header 3</a>
      </ul>
   </ul>
</ul>
<!-- End of generated Table of Contents -->

After specifying:

$toc->setOptions({'doSingleStepLevel' => 0});

the ToC will not have an indentation level inserted for level 2:

<!-- Table of Contents generated by Perl - HTML::Toc -->
<ul>
   <li><a href=#h-1>Header 1</a>
   <ul>
         <li><a href=#h-1.0.1>Header 3</a>
   </ul>
</ul>
<!-- End of generated Table of Contents -->

See the difference? One step at a time vs. skipping straight down. Both valid, just different aesthetics. 🌸


fileSpec πŸ—‚οΈ

syntax:  <regexp>
default: undef

Specifies which files should match the current level. Valid only if doLinkToFile equals 1. For an example, see Site map.


syntax:  $scalar
default: "\n<!-- End of generated Table of Contents -->\n"

String to output at end of ToC. The lil outro. πŸ’œ


groupId 🏷️

syntax:  $scalar
default: 'h'

Sets the group id attribute of a tokenGroup. With this attribute it's possible to divide the ToC into multiple groups β€” and each group has its own numbering scheme, no cap. For example, to generate a ToC of both normal headings and 'appendix' headings, specify the following ToC settings:

$toc->setOptions({
   'tokenToToc' => [{
          'tokenBegin' => '<h1 class=-appendix>'
       }, {
          'groupId' => 'appendix',
          'tokenBegin' => '<h1 class=appendix>'
   }]
});

groupToToc 🎯

syntax:  <regexp>
default: '.*'

Determines which groups to use for generating the ToC. For example, to create a ToC for groups [a-b] only, specify:

'groupToToc => '[a-b]'

This option is evaluated during both ToC generation and ToC formatting. Which enables you to generate a ToC of all groups, but β€” after generating β€” format only specified groups:

$toc->setOptions({'groupToToc' => '.*'});
$tocGenerator->generateToc($toc, ...);
    # Get ToC of all groups
$fullToc = $toc->format();
    # Get ToC of 'appendix' group only
$toc->setOptions({'groupToToc' => 'appendix'});
$appendixToc = $toc->format();

Generate everything, then show only what you want. The main character move. ✨


syntax:  $scalar
default: "\n<!-- Table of Contents generated by Perl - HTML::Toc -->\n"

String to output at begin of ToC. The lil intro. 🌈


insertionPoint πŸ“

syntax:  [<before|after|replace>] <token>
default: 'after <body>'
token:   <[/]tag{ attribute=[-|@]<regexp>}> |
         <text regexp> |
         <declaration regexp> |
         <comment regexp>

Determines the point within the source where the ToC should be inserted. When specifying a start tag as the insertion point token, attributes to be included may be specified as well. Note that the attribute value must be specified as a regular expression. For example, to specify the "<h1 class=header>" tag as insertion point:

'<h1 class=^header$>'

Examples of valid 'insertionPoint' tokens are:

'<h1>'
'</h1>'
'<!-- ToC -->'
'<!ToC>'
'ToC will be placed here'

It is also possible to specify attributes to exclude, by prefixing the value with an attributeToExcludeToken, default a minus sign (-). For example, to specify the "<h1"> tag as insertion point, excluding all "<h1 class=header>" tags:

'<h1 class=-^header$>'

See also tokenBegin. 🫢


level πŸ“Š

syntax:  number
default: 1

Number which identifies at which level the tokengroup should be incorporated into the ToC. See also: tokenToToc.


levelIndent ➑️

syntax:  number
default: 3

Sets the number of spaces each level will be indented, when formatting the ToC. Three spaces by default, because three is the moment. πŸ’…

πŸ’… levelToToc

  • syntax: <regexp>
  • default: '.*'

So this one decides which group levels actually make it into your ToC. Want a ToC that's just levels 1–2? Say it with your chest:

'levelToToc => '[1-2]'

Bestie, this option gets evaluated twice β€” once when the ToC is generated and again when it's formatted. Which means you can generate a ToC with everything, and then β€” after generating β€” pull back only the levels you want:

$toc->setOptions({'levelToToc' => '.*'});
$tocGenerator->generateToc($toc, ...);
    # Get ToC of all levels
$fullToc = $toc->getToc();
    # Get ToC of level 1 only
$toc->setOptions({'levelToToc' => '1'});
$level1Toc = $toc->getToc();

Okay the way that works is genuinely iconic ✨


πŸ”’ numberingStyle

  • syntax: [decimal|lower-alpha|upper-alpha|lower-roman|upper-roman]}
  • default: decimal

Decides which numbering style a token group gets when doLinkToToken is set to True (1). If you set it as a main ToC option, that setting becomes the default for every group. But if you set it inside a tokengroup, it overrides the default just for that particular tokengroup, like:

$toc->setOptions({
   'doNumberToken' => 1,
   'tokenToToc' => [{
      'level'          => 1,
      'tokenBegin'     => '<h1>',
      'numberingStyle' => 'lower-alpha'
   }]
});
🚨 If you're specifying "roman" style, you gotta have the Roman module installed, available from <http://www.perl.com/CPAN/modules/by-module/Roman>. No module, no roman numerals, periodt.

βš“ templateAnchorName

  • syntax: <expression|function reference>
  • default: '$groupId."-".$node'

The anchor name to use when doLinkToToken is set to True (1). This anchor name gets passed to both templateAnchorHrefBegin and templateAnchorNameBegin. You can hand it over as either an expression or a function reference. The expression can contain these variables:

$file
$groupId
$level
$node
$text      E.g. with "<h1><b>Intro</b></h1>", $text = "Intro"
$children  Text, including HTML child elements.
    E.g. with "<h1><b>Intro</b></h1>", $children = "<b>Intro</b>"

And if "templateAnchorName" is a function reference to a function that returns the anchor, like in:

$toc->setOptions({'templateAnchorName' => \&assembleAnchorName});

then the function gets called with these arguments:

$anchorName = assembleAnchorName($file, $groupId, $level, $node, $text, $children);

πŸ”— templateAnchorHrefBegin

  • syntax: <expression|function reference>
  • default: '"<a href=#$anchorName>"' or '"<a href=$file#$anchorName>"', depending on 'doLinkToFile' being 0 or 1 respectively.

The anchor reference begin token, used when doLinkToToken is set to True (1). Again β€” expression or function reference, your call. The expression may contain these variables:

$file
$groupId
$level
$node
$anchorName

If "templateAnchorHrefBegin" is a function reference to a function returning the anchor, like in:

$toc->setOptions({'templateAnchorHrefBegin' => \&assembleAnchorHrefBegin});

then the function gets called with these arguments:

$anchorHrefBegin = &assembleAnchorHrefBegin(
   $file, $groupId, $level, $node, $anchorName
);

See also: templateAnchorName, templateAnchorHrefEnd. 🫢


πŸ”š templateAnchorHrefEnd

  • syntax: <expression|function reference>
  • default: '"</a>"'

The anchor reference end token for when doLinkToToken is set to True (1). Expression or function reference, both valid. If templateAnchorHrefEnd is a function reference to a function returning the anchor end, like in:

$toc->setOptions({'templateAnchorHrefEnd' => \&assembleAnchorHrefEnd});

then the function gets called with no arguments:

$anchorHrefEnd = &assembleAnchorHrefEnd;

See also: templateAnchorHrefBegin. πŸ’–


🏷️ templateAnchorNameBegin

  • syntax: <expression|function reference>
  • default: '"<a name=$anchorName>"'

The anchor name begin token, used when doLinkToToken is set to True (1). Expression or function reference, whichever vibe you're on. The expression may contain these variables:

$file
$groupId
$level
$node
$anchorName

If "templateAnchorNameBegin" is a function reference to a function returning the anchor name, like in:

$toc->setOptions({'templateAnchorNameBegin' => \&assembleAnchorNameBegin});

then the function gets called with these arguments:

$anchorNameBegin = assembleAnchorNameBegin(
    $file, $groupId, $level, $node, $anchorName
);

See also: templateAnchorName, templateAnchorNameEnd.


πŸ”’ templateAnchorNameEnd

  • syntax: <expression|function reference>
  • default: '"</a>"'

The anchor name end token, for when doLinkToToken is set to True (1). Expression or function reference, as always. If templateAnchorNameEnd is a function reference to a function returning the anchor end, like in:

$toc->setOptions({'templateAnchorNameEnd' => \&assembleAnchorNameEnd});

then the function gets called with no arguments at all:

$anchorNameEnd = &assembleAnchorNameEnd;

See also: templateAnchorNameBegin. 🌸


🌟 templateLevel

  • syntax: <expression|function reference>
  • default: '"<li>$text"'

The expression used when formatting a ToC node. Expression or function reference, you know the drill. The expression may contain these variables:

$level
$groupId
$node
$sequenceNr
$text

If "templateLevel" is a function reference to a function returning the ToC node, like in:

$toc->setOptions({'templateLevel' => \&AssembleTocNode});

then the function gets called with these arguments:

$tocNode = &AssembleTocNode(
    $level, $groupId, $node, $sequenceNr, $text
);

πŸŽ€ templateLevelClose

  • syntax: <expression|function reference>
  • default: '"</li>\n"'

The expression to use when formatting a ToC node. May be an expression or a function reference. That's it, that's the whole thing πŸ’…


πŸͺ„ templateLevelBegin

  • syntax: <expression>
  • default: '"<ul>\n"'

Expression for formatting the begin of a ToC level. Peep templateLevel for the full list of variables you can use inside the expression. Say you wanna give every ToC level a class name for Cascading Style Sheets (CSS) β€” use this expression:

'"<ul class=\"toc_$groupId$level\">\n"'

which gives every ToC group a class name, like:

<ul class="toc_h1">
   <li>Header
</ul>

For an example, see Using CSS for ToC formatting. ✨


🫧 templateLevelEnd

  • syntax: <expression>
  • default: '"</ul>\n"'

Expression for formatting the end of a ToC level. Check templateLevel for the list of available variables to use inside the expression. The default expression is:

'"</ul>\n"'

For an example, see Using CSS for ToC formatting.


πŸ”’ templateTokenNumber

  • syntax: <expression|function reference>
  • default: '"$node &nbsp;"'

The token number to use when doNumberToken equals True (1). Expression or function reference, both work. The expression has access to these variables:

$file
$groupId
$groupLevel
$level
$node
$toc

If "templateTokenNumber" is a function reference to a function returning the token number, like in:

$toc->setOptions({'templateTokenNumber' => \&assembleTokenNumber});

then the function gets called with these arguments:

$number = &assembleTokenNumber(
    $node, $groupId, $file, $groupLevel, $level, $toc
);

🚩 tokenBegin

  • syntax: <token>
  • default: '<h1>'
  • token:
<[/]tag{ attribute=[-|@]<regexp>}> |
<text regexp> |
<declaration regexp> |
<comment regexp>

This scalar defines the token that triggers text getting dropped into the ToC. Any start tag, end tag, comment, declaration or text string can be specified. Valid 'tokenBegin' tokens look like:

'<h1>'
'</end>'
'<!-- Start ToC entry -->'
'<!Start ToC entry>'
'ToC entry'

When you're specifying a start tag, you can also specify attributes to be included. Heads up: the attribute value is used as a regular expression. So to specify the "<h1 class=header"> tag as tokenBegin:

'<h1 class=^header$>'

You can also specify attributes to exclude, by prefixing the value with an attributeToExcludeToken, which defaults to a minus sign (-). So to specify the "<h1"> tag as tokenBegin while excluding every "<h1 class=header"> tag:

'<h1 class=-^header$>'

And yes, you can specify an attribute value that has to be used as the ToC text, by prefixing the value with an attributeToTocToken, which defaults to an at sign (@). So to use the class value as ToC text:

'<h1 class=@>'

See Generate multiple ToCs for an elaborated example using the "attributeToTocToken" to generate a ToC of image "alt" attribute values.

See also: tokenEnd, tokenToToc.


🏁 tokenEnd

  • syntax: $scalar
  • default: empty string ('') or end tag counterpart of 'tokenBegin' if 'tokenBegin' is a start tag

The 'tokenEnd' definition follows the exact same rules as tokenBegin.

See also: tokenBegin, tokenToToc. πŸ’œ


πŸ“‹ tokenToToc

  • syntax: [{array of hashrefs}]
  • default:
[{
   'level'      => 1,
   'tokenBegin' => '<h1>'
}, {
   'level'      => 2,
   'tokenBegin' => '<h2>'
}, {
   'level'      => 3,
   'tokenBegin' => '<h3>'
}, {
   'level'      => 4,
   'tokenBegin' => '<h4>'
}, {
   'level'      => 5,
   'tokenBegin' => '<h5>'
}, {
   'level'      => 6,
   'tokenBegin' => '<h6>'
}]

This hash defines which tokens have to act as ToC entries. Each tokengroup can contain a groupId, level, numberingStyle, tokenBegin and tokenEnd identifier. That's your whole ToC blueprint right there πŸ‘‘


🧡 tokenUpdateBeginAnchorName

  • syntax: <string>
  • default: '<!-- #BeginTocAnchorNameBegin -->';

This token marks the begin of an anchor name, inserted by "HTML::TocInsertor". This option is used by "HTML::TocUpdator".


πŸͺ‘ tokenUpdateEndAnchorName

  • syntax: <string>
  • default: '<!-- #EndTocAnchorName -->';

This option is used by "HTML::TocUpdator", to mark the end of an inserted anchor name.

tokenUpdateBeginNumber πŸ”’

  • syntax: <string>
  • default: '<!-- #BeginTocNumber -->'

HTML::TocUpdator uses this one to mark where an inserted number starts. Bestie, it's literally just a lil flag so the updator knows where the number begins. πŸŽ€


tokenUpdateEndNumber πŸ”’

  • syntax: <string>
  • default: '<!-- #EndTocAnchorName -->'

HTML::TocUpdator uses this to mark where an inserted number ends. Yes, the default value says AnchorName and not Number β€” that's exactly what the page says, so we're leaving it exactly like that, no cap. Copy the default character for character and you'll be fine. πŸ’…


tokenUpdateBeginToc πŸ“‘

  • syntax: <string>
  • default: '<!-- #BeginToc -->'

HTML::TocUpdator uses this one to mark where an inserted ToC begins. It's giving "start of the table of contents, do not cross". ✨


tokenUpdateEndToc πŸ“‘

  • syntax: <string>
  • default: '<!-- #EndToc -->'

HTML::TocUpdator uses this to mark where an inserted ToC ends. And that's the whole options reference, bestie β€” we made it. 🫢


πŸ’€ KNOWN ISSUES πŸ’€

🐧 Cygwin

So for the test files to run on Cygwin without throwing a whole tantrum, you have to select the 'UNIX' default text file type during the Cygwin setup. That's the vibe check. 🌸

And when you're extracting the tar.gz file with WinZip, the 'TAR file smart CR/LF conversion' has to be turned off via {Options|Configuration...|Miscellaneous} β€” because otherwise the files toc.pod and ./manualTest/manualTest1.htm won't stay in UNIX format. Not me being dramatic, that's just how it is. 😭

Line endings are the villain of every story, fr fr.

πŸ‘‘ AUTHOR πŸ‘‘

Freddy Vulto <"fvulto@gmail.com"> β€” the icon, the legend, the main character who wrote this whole thing. πŸ’–


Copyright (c) 2009 Freddy Vulto. All rights reserved.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Periodt. πŸ¦‹


And that's a wrap on Toc(3), bestie! This lil gem came from perl v5.42.0 and it's dated 2025-07-25 β€” go forth and generate the prettiest tables of contents the world has ever seen. Slay. πŸ’…βœ¨πŸŽ€

πŸ“¦ where this page comes from