use strict; use warnings; use feature 'say'; use HTML::Entities; use Data::Dump qw/pp/; my $text; my %anchor_count; my @aoh_toc; my ($min,$max) = (3,6); my @stack; $stack[$min-1] = \@aoh_toc; # root while (my $line = ) { if ( $line =~ m# ^ (\s*) < \s* h([$min-$max]) \s* > (.*) \s*$ #xi ) { #say $line; my ($indent,$level,$text) = ($1,$2,$3); if ( $indent ) { # ignore indented warn "Skipping $line"; } else { my $anchor = text2anchor($text); warn "Duplicate '$anchor' " if $anchor_count{$anchor}++; $line = "$text\n"; my $a_sub = []; push @{$stack[$level-1]}, { text => $text, link => $anchor, sub => $a_sub, level => $level, }; $stack[$level] = $a_sub; } #say $line; } $text .= $line } # pp \@aoh_toc; say ""; print $text; sub text2anchor { my ($text) = @_; # trim $text =~ s/^\s+//; $text =~ s/\s+$//; # make valid indentifier my $encoded = encode_entities( $text ); # replace whitespaces $encoded =~ s/\s/_/g; return $encoded; } sub create_toc { my ($aoh_toc) = @_; for my $h_line (@$aoh_toc) { my $indent = " " x ($h_line->{level}-$min); say qq~$indent
  • $h_line->{text}
  • ~; my $a_sub = $h_line->{sub}; if ( @$a_sub ) { say "$indent"; } } } __DATA__ ...