\input opmac  \chyph
\input abchtml
%\hyperlinks\Blue\Red  \let\perex=\relax
\def\abcdir{http://petr.olsak.net/abcserial}
\activettchar"

\chap \TeX{} -- 5 (příklad makra pro generování HTML)

\perex 
Makrojazyk \TeX{}u nabízí poměrně neobvyklý způsob programování.
Předvedeme si základy tohoto jazyka na příkladu~-- generování jednoduchého
HTML souboru. Toto řešení používám při pořizování textu seriálu o \TeX{}u
pro abclinuxu.cz. Nečekejte tedy univerzálnost, je to řešení na míru jedné
konkrétní potřeby. Ovšem univerzální je nástroj, kterým to je udělané~--
makrojazyk \TeX{}u.

\sec Existence různých konvertítek

Po síti se potulují nejrůznější konvertítka z nejrůznějších formátů do
jiných, HTML mezi nimi nevyjímaje. Do jaké míry jsou schopny splnit
očekávání musíte posoudit sami. Mé očekávání nesplnilo zatím žádné. Dílem
proto, že konverze z \TeX{}u není v principu možná bez stejné interpretace
textu, jakou provádí \TeX{} samotný: \TeX{} si totiž pomocí přečtených maker
sám určuje, jakým způsobem bude číst další řádky zdrojového textu a jak je
bude interpretovat. Dílem taky proto, že v dokumentacích kladou konvertítka
často rovnost \TeX=\LaTeX{} a to mě vždy natolik vytočí, že dál už se tím
ani nezabývám. Ve většině případů také ta konvertítka považují za výchozí
formát něco jiného než zdrojový text k \TeX{}u a konverzi do \LaTeX{}u
používají jen jako skrytý mezistupeň k vygenerování PDF.

Osobně za výchozí formát dokumentu považuji zdrojový text \TeX{}u.
S tímto formátem interaktivně pracuji jako autor nebo sazeč, tj. vytvářím
jej v textovém editoru, dívám se na něj, modifikuji jej. Tento formát také
archivuji. V případě seriálu na abclinuxu mám archivován text v souborech
"tex1.tex", "tex2.tex" až "tex5.tex" 
(\ulink[\abcdir/]{zde})
a pokud budu chtít v budoucnu tento text
použít (například sestavit knihu), nebudu mít problém.
Ostatní formáty považuji za (de)generované. Někdo může mít jiný názor
a tudíž jiné požadavky na případné konvertítko.

O konverzi matematických vzorečků zrovna nedávno pojednal jeden 
\ulink[http://www.abclinuxu.cz/clanky/matematicke-vzorce-ve-webovych-strankach]
{článek na abclinuxu},
takže se k tomu nebudu podrobně vracet. Podotknul bych pouze, že řešení, které ze
skoro každého vzorečku vygeneruje pro HTML stránku obrázek, mi připadá poněkud
humpolácké: textové písmo pak ve www prohlížeči vizuálně nenavazuje na písmo
ve vzorečku. Konverze do 
\ulink[http://www.w3.org/Math/]{MathML} 
nebo něčeho podobného je tedy žádoucí. 
Bohužel ani 15 let po vzniku MathML není tento jazyk implementován
ve všech běžných webových prohlížečích, což odrazuje od dalších aktivit.

Mezi sémantickým značkováním vzorce (jako v MathLM) a značkováním pro
potřeby sazby (jako v \TeX{}u) existují principiální rozdíly, které konverzi
oběma směry komplikují nebo dokonce znemožňují. Sémantické informace (např.
zda ve vzorečku {\it f}({\it x}+1) je {\it f} označení funkce nebo je to násobící
koeficient) se při konverzi do \TeX{}u ztratí. Naopak \TeX{} nabízí plno
nástrojů na vylepšení vizuálního vzhledu vzorce (podpěry, fantómy, korekční
mezerování, atd.), kterým se věnuje celá kapitola 18 \TeX{}booku
resp.~sekce~6.8 
v \ulink[http://petr.olsak.net/tpp.html]{\TeX{}u pro pragmatiky}. 
Ty zas nejsou konvertovatelné do sémantického značkování. Navíc
většina matematiků si zjednoduší psaní vzorečků různými vlastními více či
méně obskurními makry. Na takovém zdrojovém textu si pak tupé konvertítko
matematických vzorců většinou vyláme zuby.

Ačkoli jsem matematik, osobně se vyhýbám vzorečkům v HTML stránkách jako
čert kříži. Takže ani v následující ukázce tento problém neřeším.
Důvody byly řečeny před chvílí. 


\sec \TeX{}4ht

Toto 
\ulink[http://www.tug.org/applications/tex4ht/mn.html]{konvertítko} 
je zajímavé tím, že používá pro konverzi ze zdrojového
souboru \TeX{}u přímo \TeX. Má připravenou modifikovanou sadu \LaTeX{}ových
balíčků, která je \TeX{}u podstrčena místo originálních balíčků a která
je zaměřena na problematiku přípravy DVI souboru pro další zpracování do
HTML. Dále se na výstupní DVI vrhne postprocesor, který má zase připravenu
sadu jakoby-fontů (místo skutečných fontů), ze kterých zjistí, jaká HTML
entita přísluší které pozici daného fontu. Celé mě to připadá zbytečně
komplikované, centrem je 8bitové DVI, ze kterého se pak
akcentované znaky rodí jako HTML entity.
Navíc je to pro plain\TeX{} ne zcela fungující. Takže ani tuto
možnost jsem nevyužil. 


\sec Konverze do HTML vlastními makry

Pomocí pdf\TeX{}u vytvořím 
\ulink[\abcdir/tex5.pdf]{PDF soubor}, který
obsahuje kompletní HTML kód. Pak stačí pomocí příkazu

\begtt
pdftotext -nopgbrk tex5.pdf tex5.html
\endtt
%
z něj udělat HTML soubor. Konvertor "pdftotext" exportuje do textu v
kódování UTF-8, takže stačí do preambule HTML napsat 

\begtt
<meta http-equiv="Content-Type" content="text/html; charset=UTF8">
\endtt
%
a není nutné řešit HTML entity jednotlivých znaků.

\ulink[\abcdir/tex5.tex]{Zdrojový text}
je označkován obvyklým způsobem, jak to dělám při použití OPmac.
Rozdíl je jen v tom, že je navíc načtena sada maker pomocí "\input abchtml". 

Rozebereme si nyní některá makra ze souboru
\ulink[\abcdir/abchtml.tex]{abchtml.tex} podrobněji.
Například "\sec Nadpis" (titulek je ukončen prázdným řádkem) se má proměnit 
na "<h2>Nadpis</h2>". K tomu stačí předefinovat makro "\sec" takto:

\begtt
\def\sec#1\par{\tag{h2}#1\unskip\tag{/h2}}
\endtt

Makro "\sec" si přečte svůj parametr "#1" až po "\par" (to je interní reprezentace
prázdného řádku) a vloží jej mezi "\tag{h2}" a "\tag{/h2}". 
Mezi koncem parametru a "\tag{/h2}" je "\unskip", aby se odstranila mezera z
konce titulku. Ve skutečnosti je makro "\sec" mírně složitější, vrátíme se k tomu později.

Pomocné makro "\tag" má jeden parametr bez separace (tj. parametr se píše do
složených závorek) a je definováno takto:

\begtt
\def\tag#1{\hbox{\localcolor\Red\tt<#1>}}
\endtt

Makro "\tag" tedy vkládá svůj parametr mezi znaky "<" a ">", ale navíc
to celé vytiskne uvnitř boxu ("\hbox") červeně ("\localcolor\Red"). To je jen
mírný bonus navíc, aby bylo výstupní PDF více přehledné. Po konverzi pomocí
"pdftotext" pochopitelně barvy nemají vliv.
Analogicky jako "\tag" je definováno makro "\ent{text}", které vytiskne
zeleně HTML entitu "&text;".

Zabývejme se nyní sazbou odstavce. Ve zdrojovém textu jsou odstavce odděleny
prázdnými řádky, které (jak bylo řečeno) jsou v \TeX{}u interně reprezentovány
pomocí "\par". Stačí tedy definovat:

\begtt
\def\par{\unskip\tag{/p}\endgraf}
\endtt
%
a každý prázdný řádek připojí do sazby tag konce odstavce "</p>" a následně
pomocí "\endgraf" skutečně ukončí odstavec.
Toto řešení ovšem způsobí, že více prázdných řádků pod sebou se
projeví větším počtem ukončovacích tagů. To není dobré. Skutečné makro 
je tedy ještě vylepšeno podmínkou, zda \TeX{} je ve stavu rozpracovaného
odstavce "\ifhmode". Není-li v tomto stavu, žádný tag netiskne.

\begtt
\def\par{\ifhmode\unskip\tag{/p}\fi\endgraf}
\endtt

Máme už každý odstavec ukončen správným tagem. Ještě je potřeba ho taky
správně zahájit. K tomu slouží v \TeX{}u registr "\everypar", kam můžeme
napsat, co má \TeX{} udělat na začátku každého odstavce:

\begtt
\everypar={\tag{p}}
\endtt

Hladká sazba (tj. sazba odstavců) je tím vyřešena. Dále pomocí
makra \ulink[\abcdir/vlna.tex]{vlna.tex}, 
který je součástí enc\TeX{}u, vkládám automaticky za
každou neslabičnou předložku vlnku. Uživatel ji nemusí psát. Vlnka je v
\TeX{}u definována jako nedělitelná mezera. Je potřeba ji pro potřeby
výstupu do HTML jen předefinovat:

\begtt
\def~{\ent{nbsp}}
\endtt

Zatím zmíněná makra nám ušetří při psaní HTML kódu už hodně práce.
Není potřeba psát otravné tagy na začátek a konec každého odstavce. Ve zdrojovém
dokumentu \TeX{}u stačí prázdný řádek, tedy bouchnout do klávesy Enter.
A o neslabičné předložky se taky nemusíme starat.

V tomto seriálu používám často slovo \TeX{} (a někdy i \LaTeX) a do
zdrojového textu zapisuji "\TeX" resp. "\LaTeX". Tato makra implicitně
tisknou logo se sníženým E. Pro potřeby HTML to není žádoucí, takže
definuji:

\begtt
\def\TeX{TeX}
\def\LaTeX{LaTeX}
\endtt

Mohl bych sice definovat "\def\TeX{T\tag{sub}E\tag{/sub}X}", ale moc se mi
toto řešení nelíbí.

Když chci něco v \TeX{}u zdůraznit kurzívou, píšu "{\it text}". V případě
konverze do HTML chci, aby se takový zápis přeměnil na "<i>text</i>". K tomu
stačí předefinovat makro "\it" takto:

\begtt
\def\it{\tag{i}\aftergroup\etagi}
\def\etagi{\tag{/i}}
\endtt
%
Toto makro lze číst takto: "\it" vytiskne tag "<i>" a po skončení skupiny
spustí "\etagi". Skupina je ukončena ukončovací závorkou~"}". V tomto místě
"\etagi" vytiskne ukončovací tag "</i>". Podobně je předefinováno makro
"\bf" pro přechod na tučný font.

Vrátíme se k makru "\sec", které bylo již vysvětleno, ale ve skutečnosti je
definováno takto:

\begtt
\def\sec#1\par{\medskip\notagindent \tag{h2}{\tenbf#1}\unskip\tag{/h2}\endgraf\medskip}
\endtt

Příkaz "\medskip" udělá vertikální mezeru, "\notagindent" zahájí odstavec
bez vstupního tagu "<p>", dále "\tenbf" nastaví tučný font (jen pro
přehlednost), "\endgraf" ukončí odstavec bez ukončovacího tagu "</p>" a
"\medskip" vloží další vertikální mezeru.

V tomto duchu jsou v souboru "abchtml.tex" naprogramována i ostatní použitá
makra. Celý dokument je vytištěn ve strojopisu písmem Cursor 
("\input cs-cursor"), aby se neslilo f a i do ligatury~fi. 

Soubor \ulink[\abcdir/abchtml.tex]{abchtml.tex} 
obsahuje zhruba 70 řádků docela srozumitelných
maker. Pokud někdo chce pro svou webovou prezentaci svých dokumentů
tento přístup použít, může. Stačí makra trošičku modifikovat
dle potřeb konkrétního webu, tedy například zohlednit, na jaké to bude konkrétně 
navazovat kaskádové styly anebo PHP. Je také možné navázat na použitý
JavaScript, tj. například již zmíněnou matematiku dělat MathJaxem.

Je zřejmé, že podobná sada maker by mohla posloužit ke konverzi do
\ulink[http://en.wikipedia.org/wiki/ReStructuredText]{reStructuredText}, 
na který by se pak dala použít většina dostupných
konvertítek do všemožných dalších formátů.


\sec Poznámka ke kódování

Do zdrojového textu mohu napsat například "$\alpha$" a na webové stránce po
konverzi vidím $\alpha$. Přitom znak $\alpha$ je do PDF vytištěn pomocí
matematického fontu z pozice, která vůbec neodpovídá Unicode tohoto znaku.
To ale nevadí. Font vložený do PDF má totiž ke každému znaku přidělenu nejen
pozici znaku, ale i jeho název. A konvertor "pdftotext" se ptá na název
znaku. Zjistí, že v tomto případě je název "alpha" a v Unicode tabulce
najde tento název pod číslem U+03B1. Na základě toho ví, že má pro tento
znak vytvořit UTF-8 kód 0xCE 0xB1 a vše funguje, jak má.


\sec Co když vyřadím HTML makra?

Pokud ve zdrojovém kódu 
\ulink[\abcdir/tex5.tex]{tex5.tex} 
zakomentuji příkaz "\input abchtml" a
místo toho napíšu třeba "\hyperlinks\Blue\Red \let\perex=\relax", dostanu
\ulink[\abcdir/tex5-n.pdf]{obvyklý výstup}, který je
připraven pro další zpracování. Sazeč dále rozhodne, jaký použije font,
jaké nastaví zrcadlo a další parametry sazby, jak upraví nadpisy. 
Taky zatáhne neslabičné předložky 
(např. pomocí \ulink[\abcdir/vlna.tex]{vlna.tex}) a
vyřeší přetečený řádek. Toto je typická ukázka, jak rozličný výstup lze
získat ze {\it stejného textu}, jen při použití jiných maker.

\bye
