[>a2175.html>] [<a2173.html<] [^a2.html^]
L'elaborazione SGML si compone fondamentalmente di un programma in grado di verificare la correttezza formale di un sorgente SGML in base al suo DTD. Questo tipo di programma è l'analizzatore SGML (SGML parser) e il suo compito si estende frequentemente alla generazione di un risultato intermedio, pronto per una rielaborazione successiva, normalmente attraverso un sistema di composizione tipografica.
L'elaborazione successiva richiede strumenti specifici, ma per le situazioni più semplici, dove basta rimpiazzare un marcatore con una codifica equivalente adatta a un programma di composizione tipografica particolare, si è utilizzato in passato il cosiddetto ASP: Amsterdam SGML Parser.
L'utilizzo di un analizzatore SGML, precisamente il pacchetto SP con il programma nsgmls, è una cosa consueta e attuale, mentre l'utilizzo di un analizzatore ASP può considerarsi una tecnica obsoleta. Tuttavia, l'abbinamento di nsgmls e sgmlsasp (quest'ultimo è un analizzatore ASP) è un metodo semplice e pratico per costruire i propri strumenti SGML, quando non si vuole utilizzare quello che è già a disposizione.
In sostituzione di sgmlsasp si può utilizzare anche il pacchetto SGMLSpm, il quale si compone di una serie di moduli Perl, e in particolare fornisce il programma sgmlspl, che svolge un compito simile a quello di un analizzatore ASP.
SP è il pacchetto di analisi SGML di James Clark. Si tratta dello strumento fondamentale, ed è disponibile anche su piattaforme differenti dallo Unix. In passato, al posto di SP, era disponibile il pacchetto Sgmls che comunque non era compatibile con molte caratteristiche particolari dell'SGML.
Il pacchetto SP contiene il programma nsgmls, assieme a una serie di DTD di esempio. Il programma nsgmls è tutto quello che serve per convalidare un file SGML con il suo DTD e per generare un risultato intermedio analizzabile automaticamente attraverso sgmlsasp, un accessorio del vecchio pacchetto Sgmls, o in alternativa attraverso sgmlspl, del pacchetto SGMLSpm.
nsgmls [opzioni] [identificatore_di_sistema]...
nsgmls utilizza lo standard input, oppure i file indicati in coda alla riga di comando (gli identificatori di sistema), per analizzarne il contenuto secondo l'SGML ed eventualmente per generare un output pre-elaborato.
Gli errori vengono segnalati attraverso lo standard error, mentre il risultato dell'elaborazione viene emesso attraverso lo standard output.
-c identificatore_di_sistema
Permette di specificare l'utilizzo di un catalogo, rappresentato dal file indicato come argomento dell'opzione. Questa opzione può essere specificata più volte, per richiedere l'utilizzo di più cataloghi. Se nella stessa directory del file del documento analizzato esiste un file denominato catalog
, questo viene aggiunto in coda ai cataloghi letti attraverso questa opzione. Inoltre, se esiste la variabile di ambiente SGML_CATALOG_FILES, l'elenco dei cataloghi in essa contenuti viene aggiunto in coda a tutti gli altri.
-D directory
Permette di definire una directory da utilizzare per la ricerca di file specificati negli identificatori di sistema. Sono ammissibili più opzioni -D. Se esiste la variabile di ambiente SGML_SEARCH_PATH, l'elenco di directory che questa contiene viene aggiunto in coda a quello definito attraverso l'opzione -D.
-E n_massimo_errori
Permette di stabilire il numero massimo di errori, dopo il quale nsgmls termina l'analisi. Il valore predefinito è 200.
-inome
Permette di definire un'entità parametrica, con il nome indicato, contenente la stringa INCLUDE. In pratica ciò che nel DTD dovrebbe essere definito con l'istruzione <!ENTITY % nome "INCLUDE">. Questa dichiarazione prende la precedenza su un'altra dichiarazione della stessa entità fatta in qualunque altra posizione; il suo scopo è quello di facilitare la gestione delle sezioni marcate da includere in modo condizionato.
In pratica, si definiscono nel DTD solo entità parametriche di questo tipo con il valore IGNORE, con le quali si delimitano parti di testo attraverso l'uso di sezioni marcate. Quindi, quando si vogliono includere quelle porzioni di testo, si può utilizzare questa opzione, anche più volte, per fare sì che le entità parametriche desiderate contengano invece la parola chiave INCLUDE.
-s
Sopprime l'emissione dell'output intermedio. In questo modo si limita a emettere le segnalazioni di errori attraverso lo standard error.
-p
Analizza solo il prologo, in pratica il DTD, ignorando il documento. Ciò implica, di fatto, l'uso dell'opzione -s.
$
nsgmls -s -c ~/catalogo
Si limita a convalidare il contenuto del documento proveniente dallo standard input, avvalendosi del catalogo contenuto del file ~/catalogo
.
$
nsgmls -c ~/catalogo
Convalida il contenuto del documento proveniente dallo standard input, avvalendosi del catalogo contenuto del file ~/catalogo
, generando anche il documento rielaborato opportunamente.
$
nsgmls -i annotazioni -c ~/catalogo
Come nell'esempio precedente, ma in più dichiara l'entità parametrica annotazioni contenente la parola chiave INCLUDE.
Ci sono due variabili di ambiente a cui è sensibile nsgmls: SGML_SEARCH_PATH e SGML_CATALOG_FILES. Entrambe servono a contenere l'indicazione di un elenco di percorsi, separati attraverso i soliti due punti (:).
La variabile SGML_SEARCH_PATH serve ad aggiungere altre directory a quelle che possono essere definite attraverso l'opzione -D, per la ricerca di file corrispondenti agli identificatori di sistema.
La variabile SGML_CATALOG_FILES serve ad aggiungere altri cataloghi (indicati con il loro percorso assoluto) a quelli che possono essere definiti attraverso l'opzione -c.
Queste due variabili possono essere molto importanti quando si devono fornire queste indicazioni, senza avere il controllo diretto sul comando di avvio dell'eseguibile nsgmls. In pratica, quando si installano strumenti SGML che si avvalgono di SP e c'è la necessità di indicare dove si trova il file del catalogo, oppure dove si trovano gli altri file, la modifica di queste variabili può essere l'unica soluzione.
Il risultato dell'output dell'elaborazione di un file SGML attraverso nsgmls è composto da una serie di righe di testo, di lunghezza variabile, precedute da un carattere nella prima colonna che ne definisce il significato.
In pratica, ogni riga inizia necessariamente con un codice composto da un solo carattere di «comando», e subito dopo, senza spazi aggiuntivi, inizia il contenuto di uno o più argomenti, a seconda del comando, separati da un solo carattere spazio. L'ultimo argomento (che potrebbe anche essere l'unico) può contenere spazi.
Gli «argomenti» di questi comandi possono contenere delle sequenze di escape:
\\
rappresenta una singola barra obliqua inversa (\);
\n
rappresenta la fine di una riga (record end), secondo la logica di SGML;
\
viene usato per delimitare (all'inizio e alla fine) le entità di tipo SDATA, dopo che queste sono state espanse regolarmente;
\nnn
rappresenta un carattere particolare attraverso il suo codice ottale;
nsgmls prevede un numero molto grande di caratteri di comando per distinguere il contenuto delle righe del risultato dell'elaborazione. Qui ne vengono mostrati solo alcuni, i più comuni. Gli altri sono descritti dettagliatamente nella pagina di manuale nsgmls(1).
(identificatore_generico
Una parentesi aperta rappresenta l'inizio di un elemento, nominato subito dopo (l'identificatore generico). Se questo elemento dovesse avere attributi, questi verrebbero rappresentati prima, attraverso i comandi A.
)identificatore_generico
Una parentesi chiusa rappresenta la fine di un elemento, nominato subito dopo (l'identificatore generico).
Anome_attributo valore
Specifica un attributo per il prossimo elemento. Se l'elemento possiede più attributi, si utilizzano altrettanti record di tipo A.
Il valore assegnato all'attributo si può articolare in più componenti, che qui non vengono descritte.
C
Questa lettera, che appare da sola alla fine dell'output di nsgmls, rappresenta che il contenuto del file sorgente è corretto.
Di seguito vengono descritti alcuni esempi, rappresentati da pezzi dell'output di nsgmls.
(HTML (HEAD (TITLE -Introduzione all'SGML )TITLE )HEAD (BODY ... )BODY )HTML
Quello che si vede sopra, rappresenta lo schema fondamentale di ciò che si può ottenere analizzando un file HTML. Si può osservare l'apertura e la chiusura dei vari elementi (HTML, HEAD, TITLE, HEAD, BODY). I puntini di sospensione rappresentano solo l'interruzione e la ripresa della visualizzazione dell'output.
(P -Ciao,\ncome stai?\nIo bene, e tu? )P
Rappresenta un elemento P contenente una frase, divisa in vari punti dal codice \n, che rappresenta la fine della riga (record end) secondo SGML.
ANAME IMPLIED AHREF CDATA indice.html AREL IMPLIED AREV IMPLIED ATITLE IMPLIED (A -Indice generale )A
Rappresenta un elemento A, contenente la frase «Indice generale», e una serie di attributi: NAME, HREF, REL, REV e TITLE.
C
Alla fine dell'output, il carattere di comando C rappresenta il buon fine dell'elaborazione.
Il pacchetto Sgmls è stato il predecessore di SP. Questo forniva il programma sgmls, il cui funzionamento è analogo a nsgmls anche se meno completo, e sgmlsasp, un analizzatore ASP utile ancora adesso in quanto abbinabile all'output di nsgmls.
sgmlsasp file_di_rimpiazzo...
sgmlsasp elabora lo standard input, in base al contenuto di uno o più file specificati come argomenti. Lo standard input deve essere compatibile con il formato standard di sgmls e di nsgmls, mentre i file di rimpiazzo devono rispettare il formato ASP (Amsterdam SGML Parser). Il risultato viene emesso attraverso lo standard output.
sgmlsasp è in grado di elaborare solo alcuni dei comandi contenuti nei record dell'output di nsgmls, cosa che limita in parte le funzionalità utilizzabili con l'SGML.
Il file di rimpiazzo, secondo lo standard ASP, permette di sostituire i marcatori riferiti alle entità con delle stringhe che si presume siano utili per l'elaborazione successiva del testo. Questo file può contenere dei commenti, preceduti dal simbolo di percentuale e terminati dalla fine della riga del file. Le righe bianche e quelle vuote vengono ignorate.
Le direttive si compongono di due soli elementi: il marcatore di apertura o di chiusura e la stringa da utilizzare per il rimpiazzo. Si osservi l'esempio seguente:
<titolo> + "\n\\section{" </titolo> "}" +
In questo modo, si dichiara di voler sostituire il marcatore <titolo> con la stringa \n\\section{, mentre il marcatore </titolo> va sostituito con la stringa }. Come può intuire chi conosce LaTeX, si vuole sostituire all'elemento titolo l'ambiente \section{} di LaTeX.
La stringa usata per il rimpiazzo può contenere delle sequenze di escape. Per la precisione può trattarsi di:
\\
rappresenta una singola barra obliqua inversa (\);
\"
rappresenta un apice doppio con valore letterale;
\[
rappresenta una parentesi quadra aperta con valore letterale;
\]
rappresenta una parentesi quadra chiusa con valore letterale;
\n
Pertanto, la stringa di rimpiazzo vista nell'esempio, va letta come: newline\section{.
All'inizio e alla fine della stringa di rimpiazzo può apparire il segno +. Se è presente, significa che in quel punto si richiede espressamente l'aggiunta di un'interruzione di riga. Se una stringa di rimpiazzo termina con un + e subito dopo si deve inserire un'altra stringa di rimpiazzo che è preceduta da un altro +, si ottiene comunque una sola interruzione di riga, perché il secondo + si limita a confermarla.
Una stringa di rimpiazzo può apparire su più righe, come nell'esempio seguente:
<relazione> + "\\documentstyle{article}\n" "\\begin{document}" + </relazione> + "\\end{document}" +
Quando un elemento prevede degli attributi, il contenuto di questi può essere inserito nella stringa di rimpiazzo utilizzando la notazione [nome_attributo], dove le parentesi quadre servono a delimitare questo nome, che in particolare va indicato con caratteri maiuscoli.
<etichetta> "\\label{[ID]}" </etichetta>
L'esempio mostra la sostituzione del marcatore <etichetta id=...> con la stringa \label{...}, dove i puntini di sospensione rappresentano il valore dell'attributo ID.
SGMLSpm è un pacchetto che si compone di moduli e programmi Perl, per la gestione dell'output generato da nsgmls (SP). Il modo più semplice per sfruttare le funzionalità di questo pacchetto è quello di utilizzare direttamente il programma sgmlspl, scritto ovviamente in Perl, con cui è sufficiente predisporre un file simile a quello utilizzato per la sostituzione ASP.
Qui viene mostrato soltanto il funzionamento di sgmlspl, ma il lettore tenga presente che il pacchetto SGMLSpm offre molte possibilità in più, se si vuole programmare in Perl allo scopo di elaborare l'SGML.
sgmlspl script [opzione_script]... < file_sp > file_elaborato
sgmlspl elabora quanto riceve dallo standard input generando un risultato che emette attraverso lo standard output, utilizzando le specifiche indicate nel file che deve essere indicato come primo e unico argomento, che in pratica è uno script di sgmlspl stesso.
In questo senso, eventuali argomenti successivi vengono passati direttamente allo script.
In pratica, lo standard input deve corrispondere al risultato emesso dall'analizzatore SP (nsgmls) e il file delle specifiche è un pezzo di programma Perl, scritto sfruttando le caratteristiche di SGMLSpm. È il file delle specifiche che stabilisce il modo in cui i marcatori degli elementi SGML vengono trasformati nel risultato finale.
Rispetto al meccanismo di rimpiazzo utilizzato da ASP, in questo caso si devono scrivere delle righe di codice Perl abbinate agli eventi che interessano, riferiti all'analisi del file generato da SP. Volendo, oltre a distinguere i marcatori di apertura e di chiusura degli elementi, si possono individuare anche le stringhe SDATA e altri componenti di utilizzo meno frequente. Tenendo conto che il pacchetto SGMLSpm è accompagnato da una buona documentazione, qui viene mostrato semplicemente come gestire la sostituzione dei marcatori che delimitano gli elementi SGML.
Come accennato, il file per la sostituzione (ovvero il file delle specifiche) è scritto in Perl, e in particolare, tutto è visto in forma di reazione al verificarsi di un evento:
sgml( evento, funzione_da_eseguire );
Quello appena mostrato è lo schema generale delle istruzioni da utilizzare per descrivere ciò che deve fare sgmlspl quando si verifica l'evento specificato nel primo argomento. In pratica, quando si verifica, viene eseguita la funzione del secondo argomento.
L'evento viene specificato in forma di stringa, dove in particolare la forma <ELEMENTO> rappresenta l'incontro del marcatore di apertura dell'elemento ELEMENTO, e conseguentemente, </ELEMENTO> rappresenta il marcatore di chiusura. Naturalmente, sgmlspl è in grado di intercettare molti altri tipi di eventi, che comunque non vengono mostrati qui.
È importante tenere presente che gli eventi che identificano i marcatori di apertura e di chiusura degli elementi SGML, devono essere indicati nella loro forma «normalizzata» secondo l'SGML. In pratica, questo significa che in generale devono essere annotati utilizzando esclusivamente lettere maiuscole. |
La funzione indicata come secondo argomento può essere semplicemente una stringa, intendendo che questa rappresenti ciò che si vuole emettere al posto dell'evento che si è manifestato, oppure una funzione (eventualmente un puntatore a una funzione dichiarata altrove), che probabilmente si occuperà di generare un qualche tipo di output.
Generalmente, all'interno delle funzioni da abbinare agli eventi si utilizza la subroutine output per emettere dell'output, secondo quanto prescritto dalla documentazione di SGMLSpm.
Il passaggio degli attributi contenuti eventualmente nei marcatori di apertura degli elementi SGML, non è così intuitivo come avviene nella sintassi ASP. In questo caso occorre considerare che la funzione indicata come secondo argomento riceve degli argomenti in forma di oggetti, e da questi possono essere estratte le informazioni sugli attributi SGML.
Si passa alla dimostrazione di alcuni esempi che dovrebbero essere sufficienti per mostrare l'utilizzo essenziale del file delle specifiche di sostituzione per sgmlspl.
sgml( '<RELAZIONE>', "\n\\documentstyle{article}\n\\begin{document}\n" ); sgml( '</RELAZIONE>', "\n\\end{document}\n");
Questa è la situazione più semplice, in cui ci si limita a sostituire i marcatori con una stringa conveniente (in questo caso si tratta di istruzioni LaTeX). Si osservi il fatto che le istruzioni terminano con il punto e virgola; inoltre si utilizza la sequenza \n per indicare l'inserimento di un codice di interruzione di riga.
sgml( '<RELAZIONE>', sub { output "\n\\documentstyle{article}"; output "\n\\begin{document}\n"; }); sgml( '</RELAZIONE>', sub { output "\n\\end{document}\n"; });
In questo caso, si vuole ottenere lo stesso risultato dell'esempio precedente, con la differenza che nel secondo argomento si indica effettivamente una funzione (senza nome), il cui scopo è semplicemente quello di emettere le stesse stringhe già viste precedentemente, attraverso la subroutine output.
sub relazione_apertura { output "\n\\documentstyle{article}"; output "\n\\begin{document}\n"; }); sgml( '<RELAZIONE>', \&relazione_apertura );
Questa rappresenta un'altra variante dell'esempio iniziale, in cui, per il marcatore di apertura, si fa riferimento a una subroutine esterna, indicata attraverso un puntatore alla stessa.
sgml( '<ETICHETTA>', sub{ my ($elemento,$evento) = @_; my $id = $elemento->attribute('ID')->value; output "\\label{$id}"; }); sgml( '</ETICHETTA>', '' );
Questo esempio mostra il caso di un elemento SGML che prevede l'attributo ID nel marcatore di apertura. Per estrarre il valore di questo attributo occorre agire come si vede: si distinguono gli argomenti della funzione dichiarando due variabili private corrispondenti, my ($elemento,$evento) = @_;, quindi si ottiene l'attributo richiesto dall'oggetto a cui fa riferimento la variabile $elemento: $elemento->attribute('ID')->value. Quello che si ottiene viene conservato nella variabile $id, che poi viene inserita nella stringa emessa attraverso la subroutine output.
In questo caso, il marcatore di chiusura dell'elemento viene rimpiazzato semplicemente con una stringa nulla.
sgml( '<IMMAGINE>', sub{ my ($elemento,$evento) = @_; my $file = $elemento->attribute('FILE')->value; my $altezza = $elemento->attribute('ALTEZZA')->value; output "\n\\begin{center}\n"; output "\\epsfig{file=$file,height=$altezza,angle=0}\n"; output "\\end{center}\n"; }); sgml( '</IMMAGINE>', '' );
Quello che si vede è un esempio simile a quello precedente, con la differenza che gli attributi da estrarre sono due.
sgml('<LIST>', sub { my ($element,$event) = @_; my $type = $element->attribute('TYPE')->value; if ($type eq 'ORDERED') { output "\\begin{enumerate}\n"; } elsif ($type eq 'UNORDERED') { output "\\begin{itemize}\n"; } else { die "Bad TYPE '$type' for element LIST at line " . $event->line . " in " . $event->file . "\n"; } });
Questo esempio proviene dalla documentazione di SGMLSpm, e mostra in che modo modificare il risultato della trasformazione in base al contenuto degli attributi di un elemento SGML.
Da quanto è stato mostrato, si intende che la realizzazione di uno script con le specifiche di sostituzione per l'uso con sgmlspl non rappresenta un problema. Tuttavia, assieme alla documentazione di SGMLSpm si trova uno script speciale per sgmlspl che aiuta nella sua realizzazione iniziale. Si tratta di skel.pl:
sgmlspl skel.pl < file_sp > scheletro_script_sgmlspl
Come si vede, si deve partire da un risultato generato da SP; da questo si ottiene uno scheletro per la realizzazione del proprio script di sgmlspl. In generale si tratta di qualcosa simile all'esempio seguente:
######################################################################## # SGMLSPL script produced automatically by the script sgmlspl.pl # # Document Type: SGMLTEXI # Edited by: ######################################################################## use SGMLS; # Use the SGMLS package. use SGMLS::Output; # Use stack-based output. # # Document Handlers. # sgml('start', sub {}); sgml('end', sub {}); # # Element Handlers. # # Element: SGMLTEXI sgml('<SGMLTEXI>', ""); sgml('</SGMLTEXI>', ""); # Element: HEAD sgml('<HEAD>', ""); sgml('</HEAD>', ""); # Element: ADMIN sgml('<ADMIN>', ""); sgml('</ADMIN>', ""); #... # # Default handlers (uncomment these if needed). Right now, these are set # up to gag on any unrecognised elements, sdata, processing-instructions, # or entities. # # sgml('start_element',sub { die "Unknown element: " . $_[0]->name; }); # sgml('end_element',''); # sgml('cdata',sub { output $_[0]; }); # sgml('sdata',sub { die "Unknown SDATA: " . $_[0]; }); # sgml('re',"\n"); # sgml('pi',sub { die "Unknown processing instruction: " . $_[0]; }); # sgml('entity',sub { die "Unknown external entity: " . $_[0]->name; }); # sgml('start_subdoc',sub { die "Unknown subdoc entity: " . $_[0]->name; }); # sgml('end_subdoc',''); # sgml('conforming',''); 1;
Uno script per sgmlspl è in realtà uno script Perl. In questo senso si possono dichiarare variabili globali e funzioni aggiuntive. Questo consente di accumulare dei dati e di emetterli solo quando tutte le informazioni necessarie sono state ricevute, in un ordine differente rispetto alla struttura del sorgente SGML.
Per migliorare questa possibilità, è consentita la ridirezione del flusso generato attraverso funzione output(), in modo da poterlo ripescare al momento del bisogno. Prima di vedere come funziona questa cosa, si pensi a un problema tipico: si vuole accumulare in qualche modo l'informazione contenuta nell'elemento titolo, in modo da poterla emettere nel momento appropriato.
In generale, si riesce a intercettare il marcatore di apertura e quello di chiusura dell'elemento, senza poter «afferrare» il testo contenuto. Più o meno nel modo seguente:
sgml('<TITOLO>', sub{ output "\n\\section{"; }); sgml('</TITOLO>', sub{ output "}"; });
Ma quel titolo potrebbe servire per qualche motivo. Ecco come si risolve il problema:
sgml('<TITOLO>', sub{ output "\n\\section{"; push_output('string'); }); sgml('</TITOLO>', sub{ $titolo = pop_output; output "$titolo}"; });
Attraverso l'istruzione push_output('string') viene ridiretto temporaneamente tutto il flusso verso una stringa indefinita (verrà chiarito meglio tra poco); successivamente viene prelevato il testo accumulato con l'istruzione pop_output, inserendolo nella variabile $titolo. Infine, il testo accumulato viene anche emesso nuovamente attraverso la funzione output().
Ecco come si presenta la sintassi di queste due istruzioni:
push_output( tipo[, file] )
pop_output
In pratica, la funzione push_output() ridirige il flusso generato dalla funzione output() (che viene usata anche internamente a sgmlspl. Questo flusso può essere ridiretto verso oggetti differenti, identificati da una parola chiave che va indicata come primo argomento, come si vede nella tabella 135.1.
Tabella 135.1. Tipi di ridirezione della funzione push_output().
La ridirezione verso un flusso di file già aperto, verso un file e verso una pipeline è un concetto abbastanza intuitivo. In questi casi il secondo argomento indica il flusso, il file o il comando a cui si ridirige. Per esempio:
push_output( 'handle', MIO_FILE );
invia l'output verso il file già aperto con il nome MIO_FILE;
push_output( 'file', "/tmp/pippo" );
genera il file /tmp/pippo
e vi inserisce l'output;
push_output( 'append', "/tmp/pippo" );
accoda al file /tmp/pippo
;
push_output( 'pipe', "mail tizio" );
invia un messaggio di posta elettronica all'utente tizio.
Al contrario, il comando push_output('string') non prevede un secondo argomento e invia i dati in un'area indefinita, che può essere recuperata solo attraverso la funzione pop_output. La funzione pop_output serve in generale per concludere una ridirezione precedente, mentre quando si tratta in particolare di un flusso di output ridiretto verso questa area indefinita, restituisce quanto accumulato:
push_output('string'); #... #... $recupera = pop_output; #...
Infine, push_output('nul') serve a eliminare l'output senza poterlo recuperare.
La verifica sintattica di uno script di sgmlspl può risultare difficile se non si usa un trucchetto: basta aggiungere la definizione di una funzione output() fittizia, come quella seguente:
#sub output { # local( $argument ) = $_[0]; # print "$argument"; #}
L'esempio mostra delle righe commentate. Infatti, si tratta di inserire questa funzione fittizia solo nel momento in cui si vuole eseguire un'analisi attraverso Perl, nel modo seguente:
$
perl -c pippo.spec
Qui, si intende che pippo.spec
sia lo script da controllare.
Il modo migliore per comprendere come si possono mettere insieme i vari tasselli di un sistema di composizione che parte dall'SGML, è quello di studiare un esempio elementare, che possa essere esteso facilmente. Si vuole arrivare a generare una trasformazione del sorgente SGML in LaTeX.
Quello che serve è: un DTD, che sarà rappresentato dal file relazione.dtd
; un catalogo, rappresentato dal file catalogo
; una serie di file contenenti le entità standard ISO indispensabili e adatte a LaTeX, rappresentate dai file ISOlat1.tex
, ISOnum.tex
e ISOdia.tex
; e infine un file di rimpiazzo ASP, rappresentato dal file mappa.tex
, oppure un file di specifiche per sgmlspl.
Si vuole realizzare un tipo di documento molto semplice, adatto per scrivere delle relazioni banali, composte da un titolo, una data, un corpo più o meno lungo e da una o più firme.
<!ENTITY % ISOlat1 PUBLIC "ISO 8879:1986//ENTITIES Added Latin 1//EN"> %ISOlat1; <!ENTITY % ISOdia PUBLIC "ISO 8879:1986//ENTITIES Diacritical Marks//EN"> %ISOdia; <!ENTITY % ISOnum PUBLIC "ISO 8879:1986//ENTITIES Numeric and Special Graphic//EN"> %ISOnum; <!ENTITY space " "> <!ENTITY null ""> <!shortref mappaglobale "BB" space "&#RS;B" null "B&#RE;" space "&#RS;B&#RE;" null "&#RS;&#RE;" null "#" num "%" percnt "@" commat "[" lsqb "]" rsqb "^" circ "_" lowbar "{" lcub "|" verbar "}" rcub "~" tilde > <!ELEMENT relazione - - (titolo?, data, contenuto)> <!ELEMENT titolo - o (#PCDATA)> <!ELEMENT data - o (#PCDATA)> <!ELEMENT contenuto - o (paragrafo+, firma+)> <!ELEMENT paragrafo - o (#PCDATA)> <!ELEMENT firma - o (#PCDATA)> <!usemap mappaglobale relazione>
Come si può osservare dall'esempio proposto, inizialmente vengono acquisite le entità standard, utilizzando un riferimento pubblico, secondo gli standard. Successivamente vengono definite delle entità aggiuntive e quindi una mappa di sostituzione (shortref).
Nella parte finale vengono definiti i vari elementi, a cominciare da quello che ha lo stesso nome del DTD, e si abbina l'elemento più esterno all'unica mappa di sostituzione che sia stata definita.
Il catalogo serve a individuare i file corrispondenti alle entità standard e al DTD stesso. Si tratta di poche righe (si osservi il fatto che non è stato definito un identificatore pubblico per il DTD, dal momento che si tratta di un lavoro poco importante).
PUBLIC "ISO 8879:1986//ENTITIES Added Latin 1//EN" "ISOlat1.tex" PUBLIC "ISO 8879:1986//ENTITIES Diacritical Marks//EN" "ISOdia.tex" PUBLIC "ISO 8879:1986//ENTITIES Numeric and Special Graphic//EN" "ISOnum.tex" DOCTYPE "relazione" "relazione.dtd"
Le entità standard, come tali, si possono recuperare già pronte un po' dappertutto. Eventualmente si può porre il problema di dover modificare le stringhe corrispondenti per il tipo di elaborazione che si intende fare. Di seguito vengono mostrati integralmente i file delle entità utilizzati in questo esempio. È il caso di ricordare che le stringhe di sostituzione sono pensate per LaTeX.
<!-- Questa versione del file ISOlat1 è ridotta rispetto all'originale dello standard ISO 8879. Per la precisione, sono state tolte le entità che esistono già negli altri file mostrati. --> <!-- Character entity set. Typical invocation: <!ENTITY % ISOlat1 PUBLIC "ISO 8879:1986//ENTITIES Added Latin 1//EN"> %ISOlat1; --> <!ENTITY aacute CDATA "\'a"--=small a, acute accent--> <!ENTITY Aacute CDATA "\'A"--=capital A, acute accent--> <!ENTITY acirc CDATA "\^a"--=small a, circumflex accent--> <!ENTITY Acirc CDATA "\^A"--=capital A, circumflex accent--> <!ENTITY agrave CDATA "\`a"--=small a, grave accent--> <!ENTITY Agrave CDATA "\`A"--=capital A, grave accent--> <!ENTITY aring CDATA "\aa{}"--=small a, ring--> <!ENTITY Aring CDATA "\AA{}"--=capital A, ring--> <!ENTITY atilde CDATA "\~a"--=small a, tilde--> <!ENTITY Atilde CDATA "\~A"--=capital A, tilde--> <!ENTITY auml CDATA '\"a'--=small a, dieresis or umlaut mark--> <!ENTITY Auml CDATA '\"A'--=capital A, dieresis or umlaut mark--> <!ENTITY aelig CDATA "\ae{}"--=small ae diphthong (ligature)--> <!ENTITY AElig CDATA "\AE{}"--=capital AE diphthong (ligature)--> <!ENTITY ccedil CDATA "\c c"--=small c, cedilla--> <!ENTITY Ccedil CDATA "\c C"--=capital C, cedilla--> <!ENTITY eth CDATA "\dh{}"--=small eth, Icelandic--> <!ENTITY ETH CDATA "\DH{}"--=capital Eth, Icelandic--> <!ENTITY eacute CDATA "\'e"--=small e, acute accent--> <!ENTITY Eacute CDATA "\'E"--=capital E, acute accent--> <!ENTITY ecirc CDATA "\^e"--=small e, circumflex accent--> <!ENTITY Ecirc CDATA "\^E"--=capital E, circumflex accent--> <!ENTITY egrave CDATA "\`e"--=small e, grave accent--> <!ENTITY Egrave CDATA "\`E"--=capital E, grave accent--> <!ENTITY euml CDATA '\"e'--=small e, dieresis or umlaut mark--> <!ENTITY Euml CDATA '\"E'--=capital E, dieresis or umlaut mark--> <!ENTITY iacute CDATA "\'\i{}"--=small i, acute accent--> <!ENTITY Iacute CDATA "\'I"--=capital I, acute accent--> <!ENTITY icirc CDATA "\^\i{}"--=small i, circumflex accent--> <!ENTITY Icirc CDATA "\^I"--=capital I, circumflex accent--> <!ENTITY igrave CDATA "\`\i{}"--=small i, grave accent--> <!ENTITY Igrave CDATA "\`I"--=capital I, grave accent--> <!ENTITY iuml CDATA '\"\i{}'--=small i, dieresis or umlaut mark--> <!ENTITY Iuml CDATA '\"I'--=capital I, dieresis or umlaut mark--> <!ENTITY ntilde CDATA "\~n"--=small n, tilde--> <!ENTITY Ntilde CDATA "\~N"--=capital N, tilde--> <!ENTITY oacute CDATA "\'o"--=small o, acute accent--> <!ENTITY Oacute CDATA "\'O"--=capital O, acute accent--> <!ENTITY ocirc CDATA "\^o"--=small o, circumflex accent--> <!ENTITY Ocirc CDATA "\^O"--=capital O, circumflex accent--> <!ENTITY ograve CDATA "\`o"--=small o, grave accent--> <!ENTITY Ograve CDATA "\`O"--=capital O, grave accent--> <!ENTITY oslash CDATA "\o{}"--=small o, slash--> <!ENTITY Oslash CDATA "\O{}"--=capital O, slash--> <!ENTITY otilde CDATA "\~o"--=small o, tilde--> <!ENTITY Otilde CDATA "\~O"--=capital O, tilde--> <!ENTITY ouml CDATA '\"o'--=small o, dieresis or umlaut mark--> <!ENTITY Ouml CDATA '\"O'--=capital O, dieresis or umlaut mark--> <!ENTITY szlig CDATA "\ss{}"--=small sharp s, German (sz ligature)--> <!ENTITY thorn CDATA "\th{}"--=small thorn, Icelandic--> <!ENTITY THORN CDATA "\TH{}"--=capital THORN, Icelandic--> <!ENTITY uacute CDATA "\'u"--=small u, acute accent--> <!ENTITY Uacute CDATA "\'U"--=capital U, acute accent--> <!ENTITY ucirc CDATA "\^u"--=small u, circumflex accent--> <!ENTITY Ucirc CDATA "\^U"--=capital U, circumflex accent--> <!ENTITY ugrave CDATA "\`u"--=small u, grave accent--> <!ENTITY Ugrave CDATA "\`U"--=capital U, grave accent--> <!ENTITY uuml CDATA '\"u'--=small u, dieresis or umlaut mark--> <!ENTITY Uuml CDATA '\"U'--=capital U, dieresis or umlaut mark--> <!ENTITY yacute CDATA "\'y"--=small y, acute accent--> <!ENTITY Yacute CDATA "\'Y"--=capital Y, acute accent--> <!ENTITY yuml CDATA '\"y'--=small y, dieresis or umlaut mark-->
---------
<!-- (C) International Organization for Standardization 1986 Permission to copy in any form is granted for use with conforming SGML systems and applications as defined in ISO 8879, provided this notice is included in all copies. --> <!-- Character entity set. Typical invocation: <!ENTITY % ISOnum PUBLIC "ISO 8879:1986//ENTITIES Numeric and Special Graphic//EN"> %ISOnum; --> <!ENTITY half CDATA "$\scriptstyle{1\over2}$"--=fraction one-half--> <!ENTITY frac12 CDATA "\sfrac1/2"--=fraction one-half--> <!ENTITY frac14 CDATA "\sfrac1/4"--=fraction one-quarter--> <!ENTITY frac34 CDATA "\sfrac3/4"--=fraction three-quarters--> <!ENTITY frac18 CDATA "\sfrac1/8"--=fraction one-eighth--> <!ENTITY frac38 CDATA "\sfrac3/8"--=fraction three-eighths--> <!ENTITY frac58 CDATA "\sfrac5/8"--=fraction five-eighths--> <!ENTITY frac78 CDATA "\sfrac7/8"--=fraction seven-eighths--> <!ENTITY sup1 CDATA "$^1$"--=superscript one--> <!ENTITY sup2 CDATA "$^2$"--=superscript two--> <!ENTITY sup3 CDATA "$^3$"--=superscript three--> <!ENTITY plus CDATA "$+$"--=plus sign B:-- > <!ENTITY plusmn CDATA "$\pm$"--/pm B: =plus-or-minus sign--> <!ENTITY lt CDATA "$<$"--=less-than sign R:--> <!ENTITY equals CDATA "$=$"--=equals sign R:--> <!ENTITY gt CDATA "$>$"--=greater-than sign R:--> <!ENTITY divide CDATA "$\div$"--/div B: =divide sign--> <!ENTITY times CDATA "$\times$"--/times B: =multiply sign--> <!ENTITY curren CDATA "\{curren\}"--=general currency sign--> <!ENTITY pound CDATA "\pounds{}"--=pound sign--> <!ENTITY dollar CDATA "\$"--=dollar sign--> <!ENTITY cent CDATA "\cent{}"--=cent sign--> <!ENTITY yen CDATA "\{yen\}"--/yen =yen sign--> <!ENTITY num CDATA "\#"--=number sign--> <!ENTITY percnt CDATA "\%"--=percent sign--> <!ENTITY amp CDATA "\&"--=ampersand--> <!ENTITY ast CDATA "*"--/ast B: =asterisk--> <!ENTITY commat CDATA "@"--=commercial at--> <!ENTITY lsqb CDATA "["--/lbrack O: =left square bracket--> <!ENTITY bsol CDATA "$\backslash$"--/backslash =reverse solidus--> <!ENTITY rsqb CDATA "]"--/rbrack C: =right square bracket--> <!ENTITY lcub CDATA "$\{$"--/lbrace O: =left curly bracket--> <!ENTITY horbar CDATA "{--}"--=horizontal bar--> <!ENTITY verbar CDATA "$|$"--/vert =vertical bar--> <!ENTITY rcub CDATA "$\}$"--/rbrace C: =right curly bracket--> <!ENTITY micro CDATA "$\mu$"--=micro sign--> <!ENTITY ohm CDATA "$\Omega$"--=ohm sign--> <!ENTITY deg CDATA "$^\circ$"--=degree sign--> <!ENTITY ordm CDATA "\{ordm\}"--=ordinal indicator, masculine--> <!ENTITY ordf CDATA "\{ordf\}"--=ordinal indicator, feminine--> <!ENTITY sect CDATA "\S{}"--=section sign--> <!ENTITY para CDATA "\P{}"--=pilcrow (paragraph sign)--> <!ENTITY middot CDATA "$\cdot$"--/centerdot B: =middle dot--> <!ENTITY larr CDATA "$\leftarrow$"--/leftarrow /gets A: =leftward arrow--> <!ENTITY rarr CDATA "$\rightarrow$"--/rightarrow /to A: =rightward arrow--> <!ENTITY uarr CDATA "$\uparrow$"--/uparrow A: =upward arrow--> <!ENTITY darr CDATA "$\downarrow$"--/downarrow A: =downward arrow--> <!ENTITY copy CDATA "\copyright{}"--=copyright sign--> <!ENTITY reg CDATA "\rcircle{}"--/circledR =registered sign--> <!ENTITY trade CDATA "(TM)"--=trade mark sign--> <!ENTITY brvbar CDATA "\{brvbar\}"--=broken (vertical) bar--> <!ENTITY not CDATA "$\neg$"--/neg /lnot =not sign--> <!ENTITY sung CDATA "\{sung\}"--=music note (sung text sign)--> <!ENTITY excl CDATA "!"--=exclamation mark--> <!ENTITY iexcl CDATA "{!`}"--=inverted exclamation mark--> <!ENTITY quot CDATA '{\tt\char`\"}'--=quotation mark--> <!ENTITY apos CDATA "'"--=apostrophe--> <!ENTITY lpar CDATA "("--O: =left parenthesis--> <!ENTITY rpar CDATA ")"--C: =right parenthesis--> <!ENTITY comma CDATA ","--P: =comma--> <!ENTITY lowbar CDATA "\_"--=low line--> <!ENTITY hyphen CDATA "-"--=hyphen--> <!ENTITY period CDATA "."--=full stop, period--> <!ENTITY sol CDATA "/"--=solidus--> <!ENTITY colon CDATA ":"--/colon P:--> <!ENTITY semi CDATA ";"--=semicolon P:--> <!ENTITY quest CDATA "?"--=question mark--> <!ENTITY iquest CDATA "{?`}"--=inverted question mark--> <!ENTITY laquo CDATA "\guillemotleft{}"--=angle quotation mark, left--> <!ENTITY raquo CDATA "\guillemotright{}"--=angle quotation mark, right--> <!ENTITY lsquo CDATA "{`}"--=single quotation mark, left--> <!ENTITY rsquo CDATA "{'}"--=single quotation mark, right--> <!ENTITY ldquo CDATA "{``}"--=double quotation mark, left--> <!ENTITY rdquo CDATA "{''}"--=double quotation mark, right--> <!ENTITY nbsp CDATA "~"--=no break (required) space--> <!ENTITY shy CDATA "\-"--=soft hyphen-->
---------
<!-- (C) International Organization for Standardization 1986 Permission to copy in any form is granted for use with conforming SGML systems and applications as defined in ISO 8879, provided this notice is included in all copies. --> <!-- Character entity set. Typical invocation: <!ENTITY % ISOdia PUBLIC "ISO 8879:1986//ENTITIES Diacritical Marks//EN"> %ISOdia; --> <!ENTITY acute CDATA "\'"--=acute accent--> <!ENTITY breve CDATA "\u{"--=breve--> <!ENTITY caron CDATA "\{caron\}"--=caron--> <!ENTITY cedil CDATA "\c{"--=cedilla--> <!ENTITY circ CDATA "\^{}"--=circumflex accent--> <!ENTITY dblac CDATA "\{dblac\}"--=double acute accent--> <!ENTITY die CDATA '\"'--=dieresis--> <!ENTITY dot CDATA "\."--=dot above--> <!ENTITY grave CDATA "\`"--=grave accent--> <!ENTITY macr CDATA "\="--=macron--> <!ENTITY ogon CDATA "\{ogon\}"--=ogonek--> <!ENTITY ring CDATA "\accent23"--=ring--> <!ENTITY tilde CDATA "\~{}"--=tilde--> <!ENTITY uml CDATA '\"'--=umlaut mark-->
L'ultimo componente necessario è il file di rimpiazzo ASP per sgmlsasp, oppure il file delle specifiche per sgmlspl. Vengono mostrati entrambi.
% % mappa.tex % <relazione> + "\\documentclass{article}\n" "\\begin{document}" + </relazione> + "\\end{document}" + <titolo> + "\n\\section{" </titolo> "}" + <data> + "\n" </data> "" + <contenuto> </contenuto> <paragrafo> + "\n" </paragrafo> "" + <firma> + "\n" </firma> "" +
---------
# # latex.spec # sgml( '<RELAZIONE>', sub { output "\n\\documentclass{article}\n"; output "\\begin{document}"; }); sgml( '</RELAZIONE>', "\n\\end{document}\n" ); sgml( '<TITOLO>', "\n\n\\section{" ); sgml( '</TITOLO>', "}\n" ); sgml( '<DATA>', "\n\n" ); sgml( '</DATA>', "" ); sgml( '<CONTENUTO>', "" ); sgml( '</CONTENUTO>', "" ); sgml( '<PARAGRAFO>', "\n\n" ); sgml( '</PARAGRAFO>', "" ); sgml( '<FIRMA>', "\n\n" ); sgml( '</FIRMA>', "" );
Quello che segue è un esempio di documento SGML adatto al DTD e al catalogo che è stato definito sopra.
<!doctype relazione SYSTEM> <relazione> <titolo>Relazione introduttiva su SGML</titolo> <data>31/12/1999</data> <contenuto> <paragrafo>SGML sta per Standard Generalized Markup Language. bla bla bla... Perché,... così... <paragrafo>Bla, bla, bla.... <firma>Pinco Pallino</firma> </contenuto> </relazione>
Una volta scritto un testo SGML, la prima cosa da fare è la verifica di coerenza in base al DTD. Se il file da controllare fosse relazione.sgml
, si dovrebbe utilizzare il comando seguente (si presume che il file del catalogo sia collocato nella directory corrente).
$
nsgmls -s -c ./catalogo < relazione.sgml
Una volta corretti gli errori, si può passare direttamente alla trasformazione in LaTeX, ma se lo si desidera, si può osservare l'output generato da nsgmls.
$
nsgmls -c ./catalogo < relazione.sgml
Se si tratta dell'esempio di documento mostrato in precedenza, il risultato dovrebbe essere il seguente (una riga molto lunga appare interrotta per motivi tipografici).
(RELAZIONE (TITOLO -Relazione introduttiva su SGML )TITOLO (DATA -31/12/1999 )DATA (CONTENUTO (PARAGRAFO -SGML sta per Standard Generalized Markup Language.\nbla bla bla... )PARAGRAFO (PARAGRAFO -Bla, bla, bla.... )PARAGRAFO (FIRMA -Pinco Pallino )FIRMA )CONTENUTO )RELAZIONE C
La riga che sopra appare interrotta viene riproposta, perché contiene qualche elemento che può essere importante per il principiante.
SGML sta per Standard Generalized Markup Language.\nbla bla bla... Perch\\'e,... cos\\`\\i{}...
Su questa riga, si può osservare l'effetto delle sostituzioni delle entità standard, secondo le esigenze di LaTeX.
Il comando completo per ottenere una trasformazione in LaTeX, secondo il contenuto del file di rimpiazzo (mappa.tex
), è il seguente:
$
cat relazione.sgml | nsgmls -c ./catalogo | sgmlsasp mappa.tex
Ovvero, nel caso si utilizzi sgmlspl:
$
cat relazione.sgml | nsgmls -c ./catalogo | sgmlspl latex.spec
Il risultato ottenuto attraverso lo standard output, che andrebbe ridiretto opportunamente, potrebbe apparire come quello che segue.
\documentclass{article} \begin{document} \section{Relazione introduttiva su SGML} 31/12/1999 SGML sta per Standard Generalized Markup Language. bla bla bla... Perch\'e,... cos\`\i{}... Bla, bla, bla.... Pinco Pallino \end{document}
Una volta capito come si possono utilizzare gli strumenti SGML comuni, si pongono subito due tipi di problemi: la gestione simultanea di più sistemi di composizione e l'astrazione dal problema della rappresentazione dei simboli che in uno qualunque dei sistemi di composizione richiederebbero codici speciali. Vengono analizzati questi due problemi separatamente.
Quando si organizza un DTD allo scopo di costruire un sistema SGML per la composizione finale in più formati (PostScript, HTML ed eventualmente altro ancora), occorre definire quali siano gli obiettivi, stabilendo così anche i limiti che si devono imporre nel DTD (se si pretende di generare anche un risultato in forma di file di testo puro e semplice, le immagini potranno essere inserite nel documento solo in forma di «arte ASCII»).
Dopo il progetto del DTD e del modo in cui verranno trasformati i vari elementi nelle diverse forme di composizione, si pone un ostacolo un po' fastidioso: le entità generali. Dal momento che queste dovrebbero essere definite in modo differente a seconda del tipo di composizione che si vuole ottenere, si rischia di dover gestire altrettanti cataloghi, dovendo fare riferimento a file differenti.
In un sistema SGML ben ordinato, ci dovrebbe essere un solo catalogo, e il problema della distinzione delle entità generali si può ottenere attraverso l'uso delle sezioni marcate. Infatti, dal momento che i file delle entità esterne sono parte del DTD, si possono indicare anche altre istruzioni SGML oltre a quelle di definizione delle entità generali. Quello che segue è un estratto semplificato e abbreviato dal file delle entità esterne utilizzato attualmente da ALtools (il sistema di composizione di Appunti Linux).
<!ENTITY % EntitaASCII8 "IGNORE"> <!ENTITY % EntitaLaTeX "IGNORE"> <!ENTITY % EntitaHTML "IGNORE"> <![ %EntitaASCII8 [ <!ENTITY excl CDATA "!"-- exclamation mark --> <!ENTITY quot CDATA '"'-- quotation mark --> <!ENTITY num CDATA "#"-- number sign --> ... ]]> <![ %EntitaLaTeX [ <!ENTITY excl CDATA "!"-- exclamation mark --> <!ENTITY quot CDATA '{\tt\char`\"}'-- quotation mark --> <!ENTITY num CDATA "\#"-- number sign --> ... ]]> <![ %EntitaHTML [ <!ENTITY excl CDATA "!"-- exclamation mark --> <!ENTITY quot CDATA '"'-- quotation mark --> <!ENTITY num CDATA "#"-- number sign --> ... ]]>
Nella parte iniziale vengono dichiarate le entità parametriche EntitaASCII8, EntitaLaTeX e EntitaHTML, tutte con la stringa IGNORE. In questo modo, in condizioni normali, nessuna delle istruzioni di definizioni delle entità generali verrebbe presa in considerazione. Per selezionare un gruppo soltanto, basterebbe che l'entità parametrica giusta contenesse la stringa INCLUDE. Per farlo si interviene direttamente nella riga di comando di nsgmls (SP):
cat file_sgml | nsgmls -c catalogo -ientità_parametrica | ...
In pratica, con l'opzione -i di nsgmls, si fa in modo di introdurre una dichiarazione del tipo
<!ENTITY % entità_parametrica "INCLUDE">
e questa prende automaticamente il sopravvento su qualunque altra dichiarazione analoga (della stessa entità parametrica) in qualunque altra parte del DTD.
Per tornare all'esempio mostrato del file delle entità generali, si potrebbero selezionare le entità riferite alla trasformazione in LaTeX con un comando simile a quello seguente:
$
cat mio_file.sgml | nsgmls -c ./catalogo -iEntitaLaTeX | ...
Attraverso le entità generali che si definiscono, è possibile fare in modo che il sistema di composizione finale riceva i codici adatti per tutti i simboli «strani» che si vogliono poter inserire. Tuttavia, spesso si vorrebbe poter scrivere liberamente utilizzando il minor numero possibile di macro &...;. Per la precisione, il minimo in assoluto è quello che richiede l'SGML stesso: occorre proteggere i simboli &, > e < (&, >, <). Tutto il resto, non dà alcun fastidio all'analizzatore SGML, però i programmi di composizione potrebbero avere dei problemi differenti.
Anche senza uscire dai 7 bit dell'ASCII tradizionali, se si scrive qualcosa per LaTeX, non si possono usare direttamente caratteri normalissimi come #, \, $ e altri.
Per risolvere questo problema una volta per tutte, si utilizza una tecnica che impone una rielaborazione intermedia del risultato generato da SP dall'analisi del sorgente SGML. Questa tecnica si basa sull'uso di entità generali di tipo SDATA. Quando queste vengono sostituite dallo stesso analizzatore SGML, appaiono delimitate dalla sequenza \, cosa che ne facilita l'individuazione da parte di un programma di rielaborazione.
.-----------. .--------------. | file SGML |------------------>. .<-------------| DTD + entità | (1) `-----------' | | `--------------' V V .--------. (2) | nsgmls | `--------' | V .--------------------------------------------. (3) | trasformazione dei simboli in entità SDATA | `--------------------------------------------' | V .---------------------------------------------. (4) | trasformazione delle entità SDATA in codici | | adatti al sistema di composizione finale | `---------------------------------------------' | V .---------------------------------------------------. (5) | trasformazione nel formato finale di composizione | `---------------------------------------------------' | V .-------------------------. | sistema di composizione | `-------------------------' Figura 135.1. Passaggi per risolvere il problema dell'insieme dei caratteri. |
In questo modo si perde il vantaggio di lasciare fare all'SGML la sostituzione delle entità, però ci si può limitare a intervenire solo dove serve.
Quando si decide di intraprendere questo tipo di approccio, occorre ricordare che l'elaborazione dell'output di nsgmls deve evitare di intervenire negli elementi «letterali», ovvero quelli che anche nel sistema di composizione finale vengono presi e riprodotti tali e quali. |
La descrizione seguente fa riferimento alla figura 135.1.
Le entità riferite ai simboli che possono creare problemi vengono definite in una qualche forma simbolica specificando il tipo SDATA. Per esempio, il carattere # potrebbe essere definito nel modo standard:
<!ENTITY num SDATA "[num ]"-- number sign -->
sgmls elabora il file SGML e sostituisce le entità. Quando incontra per esempio la macro #, la trasforma in \[num ]\.
Un programma di elaborazione successivo, quando incontra per esempio il carattere #, lo trasforma in quello che sarebbe stato generato se fosse stata usata la macro #; in pratica lo trasforma in \[num ]\.
A questo punto, i simboli come # che potevano provocare problemi sono stati trasformati tutti nella forma \[num ]\. Quindi, un programma si deve occupare di trasformarli nel modo adatto al sistema di composizione a cui si dovranno dare in pasto i dati. Nel caso di LaTeX, la stringa \[num ]\ viene sostituita con \\#. Nel risultato finale, LaTeX richiede solo la stringa \#, ma fino a che si resta nell'ambito del risultato generato da nsgmls, le barre oblique inverse devono essere raddoppiate.
Attraverso sgmlsasp, oppure sgmlspl, si genera il risultato finale da passare al sistema di composizione.
È raro che una distribuzione GNU/Linux si occupi di organizzare gli strumenti SGML, mentre questo sarebbe molto importante per tutti gli sviluppatori di programmi riferiti a questo standard e a quelli derivati. A questo proposito, vale la pena di osservare la distribuzione Debian che mette in pratica alcune buone idee.
Il problema fondamentale sta nello stabilire la collocazione dei DTD e dei file delle entità generali relative. Infine, si tratta di definire un catalogo unico per tutti questi DTD e per i file delle entità. I file dei DTD vengono collocati nella directory /usr/lib/sgml/dtd/
, mentre quelli delle entità si trovano nella directory /usr/lib/sgml/entities/
. A questo punto, per facilitare l'indicazione di questi file nel catalogo, questo dovrebbe trovarsi opportunamente nella directory /usr/lib/sgml/
, con il nome catalog
; in pratica, questo è poi un collegamento al file che si trova effettivamente nella directory /etc/
: /etc/sgml.catalog
. Così il file del catalogo può essere aggiornato senza interferire con la gerarchia /usr/
che deve poter essere montata in sola lettura.
Avendo organizzato tutto in questo modo, ogni volta che si installa un nuovo pacchetto di strumenti SGML, questo dovrebbe provvedere ad aggiungere nel catalogo standard tutte le dichiarazioni che lo riguardano.
La base di questa struttura nella distribuzione Debian è costituita dai pacchetti sgml-base_*.deb
e sgml-data_*.deb
.
Quando si realizza un DTD per qualche scopo, potrebbe essere importante disporre di strumenti adatti alla sua analisi, per verificare la sua coerenza con l'obiettivo che ci si pone. Sono importanti a questo proposito i programmi di servizio del pacchetto perlSGML. Qui ne vengono mostrati solo alcuni.
In generale, per fare in modo che questi programmi di analisi funzionino correttamente, è opportuno che la directory corrente nel momento in cui si avviano corrisponda a quella in cui si trova il catalogo, in maniera tale che poi da lì, possa trovare le entità che fossero state collocate eventualmente in un file esterno. Se poi il file del catalogo non si chiama |
dtd2html [opzioni] file_dtd...
Il programma dtd2html è il più appariscente nel pacchetto perlSGML. Genera un rapporto sui DTD elencati alla fine degli argomenti, in forma di ipertesto HTML.
-help
Emette un riepilogo dell'utilizzo del programma.
-catalog catalogo
Permette di indicare il nome del file contenente il catalogo SGML. In mancanza di questa opzione, viene cercato il file catalog
nella directory corrente.
-outdir directory
Permette di specificare una directory diversa da quella corrente, nella quale verranno generate le pagine HTML.
-ents
Fa in modo che venga aggiunta una pagina HTML con l'elenco delle entità dichiarate nel corpo principale del DTD.
-tree
Fa in modo che venga aggiunta una pagina HTML con l'albero degli elementi SGML collegati tra loro in base alle dipendenze relative.
$
dtd2html dtd/mio.dtd
Analizza il file ./dtd/mio.dtd
utilizzando il catalogo ./catalog
e generando i file HTML nella directory corrente.
$
dtd2html -catalog catalogo dtd/mio.dtd
Come nell'esempio precedente, specificando che il catalogo è contenuto nel file ./catalogo
.
$
dtd2html -catalog catalogo -outdir /tmp dtd/mio.dtd
Come nell'esempio precedente, richiedendo che i file HTML siano creati nella directory /tmp/
.
$
dtd2html -catalog catalogo -outdir /tmp -ents dtd/mio.dtd
Come nell'esempio precedente, richiedendo anche la generazione di una pagina dedicata alle entità dichiarate nel DTD.
$
dtd2html -catalog catalogo -outdir /tmp -ents -tree dtd/mio.dtd
Come nell'esempio precedente, richiedendo anche la generazione di una pagina contenente l'albero degli elementi.
dtddiff [opzioni] file_dtd file_dtd
Il programma dtddiff permette di confrontare due DTD, per conoscere le differenze di contenuto tra i due. Il risultato viene emesso attraverso lo standard output.
-help
Emette un riepilogo dell'utilizzo del programma.
-catalog catalogo
Permette di indicare il nome del file contenente il catalogo SGML. In mancanza di questa opzione, viene cercato il file catalog
nella directory corrente.
$
dtddiff -catalog catalogo dtd/mio.dtd dtd2/mio.dtd
Confronta i DTD ./dtd/mio.dtd
e ./dtd/mio2.dtd
, utilizzando il catalogo ./catalogo
.
1) Apparentemente, anche la distribuzione Red Hat si sta preparando per questo. Per quanto riguarda la versione 6.0, sono disponibili dei pacchetti RPM organizzati in modo simile a quelli della distribuzione Debian, nella raccolta «Powertools».