現在のノードの深さと前のノードの深さを比較することで、必要なすべての情報が得られます。
my $last_depth = -1;
while (@input) {
my $name = shift(@input);
my $depth = 0;
++$depth while $name =~ s/^\^\^//;
while ($depth <= $last_depth) {
end_dir($last_depth);
--$last_depth;
}
die if $depth != $last_depth + 1;
start_dir($depth, $name);
++$last_depth;
}
while ($last_depth > -1) {
end_dir($last_depth);
--$last_depth;
}
プログラムの残り
my %escapes = (
'&' => '&',
'<' => '<',
'>' => '>',
'"' => '"',
"'" => ''',
);
sub text_to_xml {
my ($s) = @_;
$s =~ s/([&<>'"])/$escapes{$1}/g;
return $s;
}
sub start_dir { print((' ' x $_[0]) . qq{<dir name="}.text_to_xml($_[1]).qq{">\n}); }
sub end_dir { print((' ' x $_[0]) . qq{</dir>\n}); }
my @input = split /\n/, <<'__EOI__';
root
^^aa
^^^^bb
^^cc
^^dd
__EOI__
binmode(STDOUT, ':encoding(UTF-8)');
print(qq{<?xml version="1.0"?>\n});