• Non ci sono risultati.

4.4 I parser

4.4.3 Testo critico e testimone singolo

I parser che si occupano di estrarre il testo critico e quello di un singolo testimone sono strutturati in maniera simile. Ogni elemento XML viene trasformato in un elemento HTML per mezzo di un’opportuna funzione definita nelservice evtParser (parseXMLElement()), che genera un elemento <span> che ha come classe il tagName dell’elemento e tantidata-attributes quanti sono i suoi attributi. Da tale trasforma- zione sono esclusi alcuni nodi che devono essere invece gestiti in maniera particolare (per esempio le note <note>, le interruzioni di pagina <pb> e tutti gli elementi del modulo textcritic).

Per quanto riguarda il testo critico, prima di attuare la suddetta trasformazio- ne, si procede con la trasformazione delle entrate d’apparato in opportuni elementi <evt-reading>, definiti per mezzo della nuova direttiva evtReading25. Per ogni entrata d’apparato identificata, viene generato il relativo identificativo che permette di recuperare la entry salvata nel modello nella fase di inizializzazione, in modo da evitare di ripercorrere nuovamente la sua struttura, che come abbiamo visto risulta essere un’operazione piuttosto costosa26.

Per generare il nuovo elemento HTML si utilizza dunque l’apposita funzione getEntryLemmaText(entry), che si occupa di recuperare il lemma o la lezione di un eventuale testimone di preferenza definito tra le variabili di configurazione (preferredWitness); in questo secondo caso, al nuovo elemento viene assegnata la classe autoLemma, che permetterà di distinguere graficamente le lezioni recupe- rate automaticamente sulla base del testo di preferenza, come stabilito in fase di progettazione (Fig. 2.13).

Per ogni attributo della collezione attributes della lezione in questione viene quindi creato undata-attribute, e per ogni sotto-struttura identificata all’interno del lemma viene chiamata ricorsivamente la funzione getEntryLemmaText(subEntry). Da tale operazione viene escluso l’attributo xml:id in quanto già utilizzato per assegnare l’identificativo univoco alla lezione.

Nel caso in cui la lezione in questione sia stata utilizzata per codificare una lacuna, l’elemento in output sarà identificato mediante un’opportuna classe, che ne permetterà una gestione differente.

25

La prima operazione da effettuare è l’analisi delle entrate critiche in quanto, in assenza di opportuno attributo, l’assegnazione dell’identificativo per ognuna di esse è basata sul path originale.

26Se l’entrata d’apparato non risulta presente all’interno del modello prima di creare il nuo-

vo elemento <evt-reading> si procede eseguendo il parsing sul nodo che la rappresenta e salvandola poi all’interno del modello dei dati generale, sfruttando nuovamente la funzione handleAppEntry(appNode).

var getEntryLemmaText = function(entry){ var spanElement; if (entry !== null) { spanElement = document.createElement(’evt-reading’), spanElement.setAttribute(’data-app-id’, entry.id); if (entry._lacuna) { /* Gestione lacuna */

} else if (entry.lemma !== undefined && entry.lemma !== ’’) {

for (var i in entry.content[entry.lemma].content) {

/* Recupero il contenuto della lezione, gestendo anche i sotto apparati

e gli altri elementi non appartenenti al modulo textcritic */ }

} else if (preferredWitness !== ’’) {

spanElement = getEntryWitnessReadingText(entry, preferredWitness);

spanElement.className = ’autoLemma’;

} else {

/* Gestione errore */ }

for (var key in Object.keys(entry.attributes)) {

var attrib = attribKeys[key];

var value = entry.attributes[attrib];

if (attrib !== ’xml:id’) { spanElement.setAttribute("data-"+attrib.replace(":","-"), value); } } } else { /* Gestione errore */ } return spanElement; };

La funzione getEntryWitnessReadingText(entry, wit) si occupa di recuperare il contenuto della lezione attestata in un determinato testimone e, come vedremo più avanti, sarà utilizzata anche dal parser che si occupa di estrarre il testo integrale di un singolo testimone. In essa si utilizza la proprietà witMap aggiunta all’interno dell’attributo _indexes della singola entry per identificare velocemente la lezione di riferimento.

Dopo aver trasformato tutte le entrate d’apparato e i singoli elementi XML, l’out- put generato viene salvato nel modello, in modo da evitare di eseguire nuovamente il parser quando l’utente richiede la visualizzazione del testo critico.

Per quanto riguarda il testo di un singolo testimone, il procedimento è molto simile: si crea un elemento <evt-reading> per ogni entrata d’apparato registrata, si trasformano i singoli nodi XML in opportuni elementi HTML e si salva l’output nel modello per evitare di ripetere l’esecuzione del parser se l’utente richiede più volte la visualizzazione del testimone.

Dopo aver recuperato il contenuto della lezione attestata nel testimone in questio- ne per mezzo della funzione getEntryWitnessReadingText(entry, wit), si pro-

cede recuperando le eventuali interruzioni di pagina dello specifico testimone e sal- vandole nell’apposito attributo pages appartenente all’oggetto che lo rappresenta.

parser.parseWintessPageBreaks(docDOM, witObj);

Dopodiché, si gestiscono le eventuali lacune registrate per tale testimone. parser.parseWintessLacunas(docDOM, wit);

La funzione parseWintessLacunas() procede recuperando gli apparati delimitatori di inizio e fine delle lacune del testimone in questione e, utilizzando un’espressione regolare basata sugli identificativi univoci di questi, sostituisce il testo compreso tra ogni coppia con un apposito elemento che identifica la lacuna.

parser.parseWintessLacunas = function(docDOM, wit) {

var startLacunasWit, endLacunasWit;

/* Recupero i delimitatori di lacuna iniziali e finali del testimone in questione */

if (startLacunasWit.length === endLacunasWit.length) {

for(var k = startLacunasWit.length-1; k >= 0; k--) {

var appStart = startLacunasWit[k].parentNode,

appEnd = endLacunasWit[k].parentNode,

appStartId = appStart.getAttribute("data-app-id"),

appEndId = appEnd.getAttribute("data-app-id");

var match = "<evt-reading.*data-app-id.*"+appStartId+

".*<\/evt-reading>(.|[\r\n])*?<evt-reading.*data-app-id.*"+ appEndId+".*<\/evt-reading>";

var sRegExInput = new RegExp(match, "ig"),

newHTML = appStart.outerHTML+

"<span class=’lacuna’>[LACUNA]</span>"+ appEnd.outerHTML;

docDOM.innerHTML = docDOM.innerHTML.replace(sRegExInput, newHTML); docDOM.innerHTML = evtParser.balanceXHTML(docDOM.innerHTML); }

} else {

docDOM.innerHTML = "<span class=’error’>There was a problem...</span>"; }

};

Infine, se il testimone è identificato come frammentario27, si procede estraendo dal testo completo i singoli frammenti identificati.

parser.parseFragmentaryWitnessText(docDOM, wit);

Similmente alla gestione delle lacune, l’estrazione dei frammenti di un determinato

27

Un testimone viene identificato come frammentario se nella codifica originaria esiste almeno un lemma o una variante al cui interno è stato inserito un delimitatore di testo frammentario (<startWit/> o <endWit/>), collegato al testimone in questione mediante l’apposito attributo wit.

testimone procede recuperando gli apparati delimitatori; sulla base dei loro identifi- cativi viene definita un’espressione regolare che permette di recuperare il contenuto HTML compreso tra essi.

parser.parseFragmentaryWitnessText = function(docDOM, wit) {

var startsWit, endsWit;

/* Recupero i delimitatori iniziali e finali per il testimone in questione */

var fragmentaryText = ’’;

if (starts.length === ends.length) {

for(var k = startsWit.length-1; k >= 0; k--) {

var appStart = startsWit[k].parentNode,

appEnd = endsWit[k].parentNode,

appStartId = appStart.getAttribute("data-app-id"),

appEndId = appEnd.getAttribute("data-app-id");

var match = "<evt-reading data-app-id=’"+appStartId+

".*<\/evt-reading>(.|[\r\n])*?<evt-reading data-app-id.*"+ appEndId+".*<\/evt-reading>";

var sRegExInput = new RegExp(match, "ig");

fragmentaryText = "<span class=’fragment fragment-start’></span>"+ (docDOM.innerHTML.match(sRegExInput))+

"<span class="fragment fragment-end"></span>’"+ fragmentaryText;

}

return fragmentaryText;

} else {

return "<span class=’error’>There was a problem...</span>"; }

};

Prima di essere restituito alla vista e salvato nel modello dei dati, il testo viene bilanciato, in quanto, soprattutto nel caso siano stati estratti frammenti o elimi- nate porzioni di testo identificate come lacune, l’albero HTML potrebbe presen-

tare tag aperti ma non chiusi. Tale operazione è svolta per mezzo della funzione

balanceXHTML() definita nelservice evtParser, che prende in input la stringa rap- presentativa dell’albero XHTML del documento. La prima operazione che viene ese- guita è l’eliminazione di eventualitag “rotti” (per esempio <stro anziché <strong>). Dopodiché vengono recuperati gli elementi “rotti”, ovvero quelli che non presentano

iltag di apertura o di chiusura: per mezzo di un’espressione regolare, si recuperano

tutte le etichette e si genera l’elenco deitag di apertura che non presentano un cor- rispettivo tag di chiusura. Infine, per ognuno di essi, viene generato l’appropriato tag di chiusura e opportunamente concatenato alla stringa XHTML di origine.

Nel caso particolare del bilanciamento di un testo che presenta lacune, tale fun- zione viene richiamata all’interno della funzione parseWintessLacunas() ogni volta che viene eliminata una porzione di testo.