#!/usr/bin/perl
# Převede zdroják Media Wiki (např. wiki StatMT CLIP UMIACS) do Doku Wiki (např. wiki ÚFAL MFF UK).
# (c) 2008 Dan Zeman <zeman@ufal.mff.cuni.cz>
# Licence: GNU GPL
use utf8;
use open ":utf8";
binmode(STDIN, ":utf8");
binmode(STDOUT, ":utf8");
binmode(STDERR, ":utf8");
# Načíst zdroják Media Wiki.
while(<>)
{
$wiki .= $_;
}
# Převést konstrukce Media Wiki do pseudo-HTML.
$wiki =~ s/&/&/sg;
$wiki =~ s/</</sg;
$wiki =~ s/>/>/sg;
$wiki =~ s/\[\[(.*?)\|(.*?)\]\]/<a href='$1'>$2<\/a>/sg;
$wiki =~ s/\[(http.*?) (.*?)\]/<a href='$1'>$2<\/a>/sg;
$wiki =~ s/^====\s*(.*?)\s*====$/<h4>$1<\/h4>/mg;
$wiki =~ s/^===\s*(.*?)\s*===$/<h3>$1<\/h3>/mg;
$wiki =~ s/^==\s*(.*?)\s*==$/<h2>$1<\/h2>/mg;
$wiki =~ s/^=\s*(.*?)\s*=$/<h1>$1<\/h1>/mg;
$wiki =~ s/'''(.*?)'''/<b>$1<\/b>/sg;
$wiki =~ s/''(.*?)''/<i>$1<\/i>/sg;
$wiki =~ s/<tt>(.*?)<\/tt>/<tt>$1<\/tt>/sg;
$wiki =~ s/<sub>(.*?)<\/sub>/<sub>$1<\/sub>/sg;
$wiki =~ s/<sup>(.*?)<\/sup>/<sup>$1<\/sup>/sg;
$wiki =~ s/<pre>(.*?)<\/pre>/<pre>$1<\/pre>/sg;
$wiki =~ s/<span (.*?)>(.*?)<\/span>/<span $1>$2<\/span>/sg;
$wiki =~ s/^\*\*\*\*\s*/<uli4>/mg;
$wiki =~ s/^\*\*\*\s*/<uli3>/mg;
$wiki =~ s/^\*\*\s*/<uli2>/mg;
$wiki =~ s/^\*\s*/<uli1>/mg;
# Tabulky mají složitější syntax, takže si nevystačíme pouze s regulárními výrazy.
while($wiki =~ s/(\{\|.*?\|\})/<_table_being_read_>/s)
{
my $tabulka = $1;
push(@tabulky, dekodovat_tabulku($tabulka));
$wiki =~ s/<_table_being_read_>/<table$#tabulky>/s;
}
# Převést pseudo-HTML na konstrukce Doku Wiki.
$wiki =~ s/<a href='(.*?)'>(.*?)<\/a>/[[$1|$2]]/sg;
$wiki =~ s/<h1>(.*?)<\/h1>/======$1======/mg;
$wiki =~ s/<h2>(.*?)<\/h2>/=====$1=====/mg;
$wiki =~ s/<h3>(.*?)<\/h3>/====$1====/mg;
$wiki =~ s/<h4>(.*?)<\/h4>/===$1===/mg;
$wiki =~ s/<b>(.*?)<\/b>/**$1**/sg;
$wiki =~ s/<i>(.*?)<\/i>/\/\/$1\/\//sg;
$wiki =~ s/<tt>(.*?)<\/tt>/''$1''/sg;
$wiki =~ s/<pre>(.*?)<\/pre>/<code>$1<\/code>/sg;
$wiki =~ s/(<span .*?>.*?<\/span>)/<html>$1<\/html>/sg;
$wiki =~ s/<uli1>/ * /mg;
$wiki =~ s/<uli2>/ * /mg;
$wiki =~ s/<uli3>/ * /mg;
$wiki =~ s/<uli4>/ * /mg;
# Tabulky mají složitější syntax, takže si nevystačíme pouze s regulárními výrazy.
while($wiki =~ s/<table(\d+)>/<_table_being_written_>/s)
{
my $index = $1;
my $tabulka = zakodovat_tabulku($tabulky[$index]);
$wiki =~ s/<_table_being_written_>/$tabulka/s;
}
$wiki =~ s/>/>/sg;
$wiki =~ s/</</sg;
$wiki =~ s/&/&/sg;
# Dokuwiki neumí většinu entit HTML, proto dekódovat i ty < a >, které už byly v kódu MediaWiki.
$wiki =~ s/>/>/sg;
$wiki =~ s/</</sg;
# Vypsat převedený zdroják na standardní výstup.
print($wiki);
#------------------------------------------------------------------------------
# Rozebere tabulku v syntaxi Media Wiki a uloží ji jako pole buněk.
#------------------------------------------------------------------------------
sub dekodovat_tabulku
{
my $tabulka = shift;
# Rozsekat kód tabulky na řádky.
my @radky_kodu = split(/\r?\n/, $tabulka);
# Projít řádky kódu, přečíst parametry celé tabulky a rozdělit kód podle řádků tabulky (což není totéž jako řádky kódu).
my $atributy_tabulky;
my @radky_tabulky;
foreach my $radek (@radky_kodu)
{
if($radek =~ m/^\{\|(.*)/)
{
$atributy_tabulky = $1;
}
elsif($radek =~ m/^\|([^-\|\}].*)/)
{
# Umazat úvodní svislítko.
$radek = $1;
$radek =~ s/^\s+//;
$radek =~ s/\s+$//;
my @bunky = split(/\s*\|\|\s*/, $radek);
# Projít buňky a oddělit atributy od obsahu.
foreach my $bunka (@bunky)
{
my %bunka;
if($bunka =~ m/^(.*?)\|(.*)$/)
{
my $atributy = $1;
$bunka{obsah} = $2;
my @atributy = split(/\s+/, $atributy);
foreach my $atribut (@atributy)
{
# $atribut nemůže obsahovat mezery, protože na mezerách jsme odsekávali atributy od sebe.
# Nemusíme se proto starat o mezery v následujícím regulárním výrazu.
if($atribut =~ m/^(.+?)=(.*)$/)
{
$bunka{$1} = $2;
}
else
{
$bunka{$atribut}++;
}
}
}
else
{
$bunka{obsah} = $bunka;
}
# V původním poli buněk nahradit řetězec odkazem na hash.
$bunka = \%bunka;
}
push(@radky_tabulky, \@bunky);
}
}
# Vytvořit hash z atributů a matice buněk a vrátit odkaz na něj.
my %tabulka =
(
'atributy' => $atributy_tabulky,
'radky' => \@radky_tabulky
);
return \%tabulka;
}
#------------------------------------------------------------------------------
# Vypíše tabulku v syntaxi Doku Wiki.
#------------------------------------------------------------------------------
sub zakodovat_tabulku
{
my $tabulka = shift; # odkaz na hash s atributy a maticí buněk
my $kod;
# Dokuwiki neumí rowspany. Projít tabulku a vložit místo nich prázdné buňky.
for(my $i = 0; $i<=$#{$tabulka->{radky}}; $i++)
{
for(my $j = 0; $j<=$#{$tabulka->{radky}[$i]}; $j++)
{
if(exists($tabulka->{radky}[$i][$j]{rowspan}))
{
# Na každý následující řádek v rowspanu přidat do příslušného místa prázdnou buňku.
for(my $k = $i+1; $k<=$i+$tabulka->{radky}[$i][$j]{rowspan}-1; $k++)
{
# Pokud má aktuální buňka také colspan, nezapomenout ho okopírovat i do vkládané prázdné buňky.
my %bunka = ('obsah' => '');
if(exists($tabulka->{radky}[$i][$j]{colspan}))
{
$bunka{colspan} = $tabulka->{radky}[$i][$j]{colspan};
}
splice(@{$tabulka->{radky}[$k]}, $j, 0, \%bunka);
}
}
}
}
# Dokuwiki špatně snáší, když všechny řádky tabulky nemají stejný počet buněk.
# Zjistit počet buněk v nejdelším řádku tabulky.
my $max_delka_radku = 0;
foreach my $radek (@{$tabulka->{radky}})
{
my $delka_radku = 0;
foreach my $bunka (@{$radek})
{
if(exists($bunka->{colspan}))
{
$delka_radku += $bunka->{colspan};
}
else
{
$delka_radku++;
}
}
$max_delka_radku = $delka_radku if($delka_radku>$max_delka_radku);
}
# Doplnit řádky prázdnými buňkami na maximální počet.
foreach my $radek (@{$tabulka->{radky}})
{
my $delka_radku = 0;
foreach my $bunka (@{$radek})
{
if(exists($bunka->{colspan}))
{
$delka_radku += $bunka->{colspan};
}
else
{
$delka_radku++;
}
}
# Vlastní doplňování začíná tady.
for(my $i = $delka_radku+1; $i<=$max_delka_radku; $i++)
{
push(@{$radek}, {'obsah' => ''});
}
}
# Zakódovat tabulku v syntaxi Doku Wiki.
foreach my $radek (@{$tabulka->{radky}})
{
$kod .= join('', map
{
my $vysledek = $_->{obsah};
$vysledek =~ s/^\s+//s;
$vysledek =~ s/\s+$//s;
if($_->{align} eq "center")
{
$vysledek = " $vysledek ";
}
elsif($_->{align} eq "left")
{
$vysledek = " $vysledek ";
}
elsif($_->{align} eq "right")
{
$vysledek = " $vysledek ";
}
else
{
$vysledek = " $vysledek ";
}
$vysledek = '|'.$vysledek;
for(my $i = 2; $i<=$_->{colspan}; $i++)
{
$vysledek .= '|';
}
$vysledek;
}
(@{$radek}))."|\n";
}
return $kod;
}