[successivo] [precedente] [inizio] [fine] [indice generale] [violazione GPL] [translators] [docinfo] [indice analitico] [volume] [parte]


Capitolo 250.   Elaborazione SGML

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 (il secondo è 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.

250.1   SP

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.

250.1.1   $ nsgmls

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.

Alcune opzioni

-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.

Esempi

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.

250.1.2   Variabili di ambiente

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.

250.1.3   Formato dell'output

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:

Alcuni comandi

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, 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.

Esempi

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.

250.2   Sgmls

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.

250.2.1   $ sgmlsasp

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.

250.2.2   File di rimpiazzo

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:

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.

250.3   SGMLSpm

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.

250.3.1   $ sgmlspl

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.

250.3.2   File con le specifiche di sostituzione

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( eventofunzione_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, da cui 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.

Esempi
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.

250.3.3   Scheletro pronto con skel.pl

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;

250.3.4   Ridirezione dell'output e altre sofisticazioni

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 250.1.

Tabella 250.1. Tipi di ridirezione della funzione push_output().

Tipo Descrizione
'handle' Ridirige verso un flusso aperto (file handle indicato nel secondo argomento.
'file' Ridirige verso un file che viene creato per l'occasione.
'append' Ridirige aggiungendo a un file esistente.
'pipe' Ridirige inviando allo standard input del comando indicato.
'string' Ridirige in un'area temporanea.
'nul' Perde l'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.

250.3.5   Verifica sintattica secondo Perl

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.

250.4   Esempio di un mini-sistema SGML

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.

250.4.1   Il DTD

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, abbinando l'elemento più esterno all'unica mappa di sostituzione che sia stata definita.

250.4.2   Il catalogo

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"

250.4.3   Le entità standard

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-->

250.4.4   Rimpiazzo ASP

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>', "" );

250.4.5   I documenti SGML

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&eacute;,... cos&igrave;...

<paragrafo>Bla, bla, bla....

<firma>Pinco Pallino</firma>

</contenuto>
</relazione>

250.4.6   I comandi necessari

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}

250.5   Lo scalino successivo

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.

250.5.1   Gestione simultanea di più sistemi di composizione

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).

<![CDATA[
<!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 | ...

250.5.2   Insieme di caratteri

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 < (&amp;, &gt;, &lt;). 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.

Figura 250.1. Passaggi per risolvere il problema dell'insieme dei caratteri.

.-----------.                                       .--------------.
| 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 |
                      `-------------------------'

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 250.1.

  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 -->
  2. sgmls elabora il file SGML e sostituisce le entità. Quando incontra per esempio la macro &num;, la trasforma in \|[num   ]\|.

  3. 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 &num;; in pratica lo trasforma in \|[num   ]\|.

  4. 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.

  5. Attraverso sgmlsasp, oppure sgmlspl, si genera il risultato finale da passare al sistema di composizione.

250.6   Organizzazione degli strumenti SGML in una distribuzione GNU/Linux

È 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.(1)

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/share/sgml/dtd/, mentre quelli delle entità si trovano nella directory /usr/share/sgml/entities/. A questo punto, per facilitare l'indicazione dei file nel catalogo, questo dovrebbe trovarsi opportunamente nella directory /etc/sgml/, con il nome 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.

250.7   perlSGML: analisi di un DTD

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 catalog, occorre usare l'opzione opportuna per indicare il nome corretto.

250.7.1   $ dtd2html

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.

Alcune opzioni

-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.

Esempi

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.

250.7.2   $ dtddiff

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.

Alcune opzioni

-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.

Esempi

dtddiff -catalog catalogo dtd/mio.dtd dtd2/mio.dtd

Confronta i DTD ./dtd/mio.dtd e ./dtd/mio2.dtd, utilizzando il catalogo ./catalogo.

Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org

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».


Dovrebbe essere possibile fare riferimento a questa pagina anche con il nome elaborazione_sgml.html

[successivo] [precedente] [inizio] [fine] [indice generale] [violazione GPL] [translators] [docinfo] [indice analitico]