Esercizio - XML ben formato e valido con una DTD per le prenotazioni (applicazione web)
In questa pagina 5
Contesto. Applicazione di prenotazione delle aule, con le tabelle aula(id, nome, posti) e prenotazione(id, aula_id, giorno, ora_inizio, ora_fine, studente) (Architettura delle applicazioni web - browser, server web e livelliUn'applicazione web è distribuita su più livelli (tier): presentazione (browser: HTML, CSS, JavaScript), logica applicativa (server web e application server) e dati (DBMS). Il client invia richieste HTTP, il server risponde; HTTP è senza stato, quindi lo stato dell'utente viaggia in cookie e sessioni. Il web server serve file statici, l'application server (container, per esempio Tomcat per le servlet Java) esegue codice che genera risposte dinamiche; spesso il web server fa da reverse proxy davanti all'application server. Il browser trasforma i byte della risposta in una pagina: decodifica, tokenizzazione e costruzione del DOM, CSS che diventa CSSOM, render tree, layout (reflow), paint e composizione; un script senza defer o async blocca il parsing, il CSS blocca il rendering. Origine = schema + host + porta; la same-origin policy limita ciò che uno script può leggere da altre origini. Web 1.0: pagine generate dal server, ogni azione ricarica la pagina; Web 2.0: AJAX, contenuti degli utenti, servizi REST; Web 3.0: dati con significato esplicito (RDF, linked data).Architettura delle applicazioni web - browser, server web e livelli →). Il segretario del dipartimento vuole esportare i dati in XML per un altro programma. Teoria: Linguaggi di markup - SGML, HTML e XMLUn linguaggio di markup aggiunge al testo marcatori che ne descrivono la struttura. SGML (ISO 8879, 1986) è il metalinguaggio da cui derivano HTML fino alla 4.01 e XML 1.0 (W3C, 1998, un sottoinsieme semplificato); HTML5 ha un proprio algoritmo di parsing, tollerante, e non è né SGML né XML. Un documento XML è ben formato se rispetta la sintassi (un'unica radice, tag annidati e chiusi, attributi tra virgolette, nomi con maiuscole e minuscole distinte, entità per i caratteri speciali) ed è valido se in più rispetta uno schema. La DTD dichiara elementi (ELEMENT: EMPTY, ANY, #PCDATA, sequenza con la virgola, scelta con |, cardinalità ? * +) e attributi (ATTLIST: CDATA, ID, IDREF, enumerazioni; #REQUIRED, #IMPLIED, #FIXED); non ha tipi di dato e non conosce i namespace. XML Schema (XSD) è scritto in XML e ha tipi (xs:date, xs:positiveInteger), restrizioni con pattern, minOccurs e maxOccurs, key e keyref. I namespace (xmlns, xmlns:prefisso) identificano il vocabolario con un URI; gli attributi senza prefisso non appartengono a nessun namespace. XML è rigido e adatto a documenti e configurazioni (web.xml, pom.xml), HTML è tollerante e ha un vocabolario fisso; JSON è l'alternativa più compatta per scambiare dati e non ha attributi, schema standard o contenuto misto.Linguaggi di markup - SGML, HTML e XML → (buona formazione, DTD, XML Schema) e Web service, XML, JSON, SOAP e RESTUn web service e' un servizio software accessibile via rete da altri programmi, con messaggi in formato standard su HTTP; i formati di dati sono XML (marcatori annidati, attributi, namespace, validazione con XSD) e JSON (RFC 8259: oggetti, array, stringhe, numeri, true, false, null; piu' compatto e diretto per i linguaggi di programmazione); SOAP e' un protocollo di messaggi XML (Envelope con Header facoltativo e Body, Fault per gli errori) inviati di solito con una POST HTTP e descritti da un file WSDL; REST e' uno stile architetturale (Fielding) in cui il servizio espone risorse identificate da URI e le manipola con i metodi HTTP: GET legge, POST crea, PUT sostituisce, PATCH modifica, DELETE elimina, con codici di stato significativi (200, 201 con Location, 204, 400, 404, 409), senza stato sul server, con cache e interfaccia uniforme.Web service, XML, JSON, SOAP e REST → (XML e JSON). Il documento esportato, una volta corretto, è quello della nota.
Parte 1 - Documento ben formato
Il documento seguente è stato scritto a mano. Trovare tutti gli errori di buona formazione (non ci sono ancora né DTD né schema) e dire la correzione. Il documento ha cinque errori.
<?xml version="1.0" encoding="UTF-8"?>
<prenotazioni>
<aula id=a1 posti="80"><nome>Aula A1</nome></aula>
<prenotazione id="p1" aula="a1">
<giorno>2026-10-19</giorno>
<ora_inizio>09:00</ora_inizio>
<ora_fine>11:00</ora_inine>
<studente>Rossi & Bianchi</studente>
</prenotazione>
<prenotazione id="p2" aula="a1">
<giorno>2026-10-19</giorno>
<ora_inizio>14:00</ora_inizio>
<ora_fine>16:00</ora_fine>
<Studente>Verdi</studente>
</prenotazione>
</prenotazioni>
<nota>fine elenco</nota>Soluzione.
| riga | errore | correzione |
|---|---|---|
| 3 | il valore dell'attributo id=a1 non è fra virgolette |
id="a1" |
| 7 | <ora_fine> si chiude con </ora_inine>: nome diverso, tag non annidato correttamente |
</ora_fine> |
| 8 | & non seguito da un nome di entità: nel testo deve essere & |
Rossi & Bianchi |
| 14 | <Studente> e </studente>: i nomi distinguono maiuscole e minuscole |
<studente>Verdi</studente> |
| 17 | dopo la radice prenotazioni c'è un secondo elemento, nota: un documento ha una sola radice |
toglierlo, o metterlo dentro la radice |
- Un parser XML si ferma al primo errore: per questo gli errori si trovano uno alla volta con lo strumento, ma per ispezione si cercano tutti. Verificati con un parser, uno per volta: gli errori sono quelli descritti (attributo senza virgolette, tag non corrispondente alla riga 7,
&non valido alla riga 8, tag non corrispondente alla riga 14, testo dopo l'elemento radice alla riga 17); dopo le cinque correzioni il documento è ben formato. - Un parser HTML invece accetterebbe quasi tutto: è la differenza principale fra i due linguaggi.
Parte 2 - Documento valido: la DTD
Il segretario descrive il formato:
- la radice è
prenotazioni; contiene almeno un'aula, poi zero o più prenotazioni; - un'
aulaha un attributoid(identificatore unico, obbligatorio), un attributoposti(obbligatorio) e un figlionomedi testo; - una
prenotazioneha un attributoid(identificatore unico, obbligatorio), un attributoaulache fa riferimento a un'aula (obbligatorio) e quattro figli in quest'ordine:giorno,ora_inizio,ora_fine,studente, tutti di testo.
Scrivere la DTD e spiegare perché id="a1" e non id="1".
Soluzione.
<!ELEMENT prenotazioni (aula+, prenotazione*)>
<!ELEMENT aula (nome)>
<!ATTLIST aula
id ID #REQUIRED
posti CDATA #REQUIRED>
<!ELEMENT nome (#PCDATA)>
<!ELEMENT prenotazione (giorno, ora_inizio, ora_fine, studente)>
<!ATTLIST prenotazione
id ID #REQUIRED
aula IDREF #REQUIRED>
<!ELEMENT giorno (#PCDATA)>
<!ELEMENT ora_inizio (#PCDATA)>
<!ELEMENT ora_fine (#PCDATA)>
<!ELEMENT studente (#PCDATA)>aula+, prenotazione*: la virgola è la sequenza, quindi prima le aule e poi le prenotazioni;+= una o più,*= zero o più.ID= identificatore unico in tutto il documento;IDREF= riferimento che deve coincidere con unIDesistente.postièCDATA(testo qualsiasi: la DTD non ha il tipo numero).- Perché
a1e non1? Un valore di tipoIDè un nome XML: non può cominciare con una cifra. Inoltre è unico per tutto il documento, non per tipo di elemento: l'aula 1 e la prenotazione 1 del database avrebbero lo stessoid, e un documento conid="1"due volte non sarebbe valido. Il prefisso (a,p) risolve entrambi i problemi. - Il documento corretto della parte 1 è valido con questa DTD se si aggiunge
<!DOCTYPE prenotazioni SYSTEM "prenotazioni.dtd">dopo la dichiarazione XML (le righe digiorno,ora_inizio,ora_fine,studenteci sono tutte nell'ordine giusto).
Parte 3 - Documenti ben formati ma non validi
Il documento seguente (con la DTD della parte 2) è ben formato. Trovare le violazioni della DTD.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE prenotazioni SYSTEM "prenotazioni.dtd">
<prenotazioni>
<aula id="a1" posti="80"><nome>Aula A1</nome></aula>
<aula id="a2"><nome>Aula B2</nome></aula>
<prenotazione id="p1" aula="a1">
<giorno>2026-10-19</giorno>
<ora_inizio>09:00</ora_inizio>
<ora_fine>11:00</ora_fine>
<studente>Rossi</studente>
</prenotazione>
<prenotazione id="p2" aula="a1">
<giorno>2026-10-19</giorno>
<ora_fine>16:00</ora_fine>
<ora_inizio>14:00</ora_inizio>
<studente>Bianchi</studente>
</prenotazione>
<prenotazione id="p3" aula="a9">
<giorno>2026-10-20</giorno>
<ora_inizio>10:00</ora_inizio>
<ora_fine>12:00</ora_fine>
<studente>Verdi</studente>
<note>urgente</note>
</prenotazione>
<prenotazione id="p1" aula="a2">
<giorno>2026-10-21</giorno>
<ora_inizio>09:00</ora_inizio>
<ora_fine>13:00</ora_fine>
<studente>Rossi</studente>
</prenotazione>
</prenotazioni>Soluzione. Ci sono cinque violazioni (riga e messaggio del parser validante del JDK 21, che riporta tutte le violazioni):
| riga | violazione | regola della DTD |
|---|---|---|
| 5 | l'aula a2 non ha l'attributo posti |
posti CDATA #REQUIRED |
| 17 | ora_fine viene prima di ora_inizio |
la sequenza (giorno, ora_inizio, ora_fine, studente) è ordinata |
| 23 | l'elemento note non è dichiarato, e il contenuto di p3 non corrisponde più alla sequenza (messaggio ripetuto alla riga 24) |
nessuna dichiarazione note; la sequenza ha esattamente quattro figli |
| 25 | id="p1" compare due volte |
un ID è unico nel documento |
| 31 | aula="a9" non corrisponde a nessun ID |
un IDREF deve riferirsi a un ID esistente |
- Nessun errore riguarda i valori: la DTD non controlla che
giornosia una data o cheora_finesia dopoora_inizio(nella prenotazionep3, 10:00-12:00, va tutto bene; ma un<giorno>pippo</giorno>sarebbe stato accettato). Per questo servono tipi (XML Schema) e, per i vincoli fra campi diversi, l'applicazione e il database (CHECK (ora_fine > ora_inizio)).
Parte 4 - Estensione della DTD
Si vuole aggiungere a ogni prenotazione una nota facoltativa (elemento nota, testo, dopo studente) e un attributo stato che vale confermata oppure annullata, con confermata come valore predefinito. Modificare la DTD.
Soluzione.
<!ELEMENT prenotazione (giorno, ora_inizio, ora_fine, studente, nota?)>
<!ATTLIST prenotazione
id ID #REQUIRED
aula IDREF #REQUIRED
stato (confermata | annullata) "confermata">
<!ELEMENT nota (#PCDATA)>nota?: zero o una volta, in coda alla sequenza; va dichiarato anche l'elementonota.stato (confermata | annullata) "confermata": un'enumerazione con valore predefinito: se l'attributo manca, il parser validante lo consideraconfermata. Constato="sospesa"il documento non è valido (verificato:Attribute "stato" with value "sospesa" must have a value from the list "confermata annullata"); il documento constato="annullata"e unanotaè valido.- Il vecchio documento resta valido:
notaè facoltativa estatoha un predefinito.
Parte 5 - XML Schema e JSON
a) Perché per ora_inizio e ora_fine non basta xs:time? Scrivere il tipo Ora.
xs:time richiede i secondi (09:00:00): con 09:00 il documento non è valido. Si definisce una restrizione di xs:string con un pattern ore:minuti:
<xs:simpleType name="Ora">
<xs:restriction base="xs:string">
<xs:pattern value="([01][0-9]|2[0-3]):[0-5][0-9]"/>
</xs:restriction>
</xs:simpleType>Verificato con il validatore del JDK 21 sullo schema completo: 09:00 è accettata, 25:00 no (Value '25:00' is not facet-valid with respect to pattern). Il pattern descrive: due cifre da 00 a 23, due punti, due cifre da 00 a 59. Anche con questo tipo non si controlla ora_fine > ora_inizio.
b) Scrivere la prenotazione p1 in JSON come la fornirebbe l'API REST, e dire che cosa cambia rispetto all'XML.
{"id": 1, "aula_id": 1, "giorno": "2026-10-19", "ora_inizio": "09:00", "ora_fine": "11:00", "studente": "Rossi"}- I numeri sono numeri (
1, non"1"), e i prefissipeaspariscono: nel database e nell'APIideaula_idsono interi; l'IDXML è un nome. - L'attributo
aula(XML) e l'elemento figliogiornodiventano entrambi chiavi dello stesso oggetto: la differenza fra attributo ed elemento si perde. - Si vede la scelta: per scambiare dati fra pagina e server si usa JSON (più compatto,
JSON.parselo legge in una riga: JavaScript - linguaggio, DOM ed eventiJavaScript (standard ECMAScript, Ecma-262) è il linguaggio dei browser: tipizzato dinamicamente, con sette tipi primitivi (number, string, boolean, undefined, null, bigint, symbol) e gli oggetti (anche array e funzioni); typeof null vale "object" per un errore storico; == converte i tipi, === no (si usa sempre ===); valori falsy: false, 0, 0n, "", null, undefined, NaN. let e const hanno visibilità di blocco e una zona morta prima della dichiarazione, var visibilità di funzione e hoisting; const impedisce di riassegnare il nome, non di modificare l'oggetto. Funzioni: dichiarazione (hoisted), espressione, arrow function (this lessicale), parametri predefiniti, rest e spread, destructuring. Array: map, filter, reduce, find, some, every, sort (senza comparatore ordina come stringhe). Closure: una funzione ricorda le variabili dell'ambiente in cui è nata. Eventi: addEventListener; propagazione in tre fasi (cattura, target, bolla), stopPropagation, preventDefault, delegazione con event.target e closest. DOM: albero di nodi; querySelector, createElement, append, replaceChildren, textContent (sicuro) contro innerHTML (rischio di XSS), classList, dataset. Moduli ES (type="module", import e export) sono differiti e in modalità strict. Event loop: un solo thread, call stack, coda dei task (setTimeout, eventi) e coda dei microtask (promise, await) svuotata dopo ogni task: l'esecuzione asincrona (fetch, async e await, Promise.all) è alla base di AJAX e il codice lungo blocca la pagina.JavaScript - linguaggio, DOM ed eventi →); XML conviene per documenti con contenuto misto, per schemi rigorosi e per i file di configurazione (web.xml,pom.xml).
Errori tipici
- Dire "valido" per un documento che è solo ben formato.
- Non vedere che
</ora_inine>o<Studente>sono errori: i nomi devono coincidere esattamente. id="1"per unID: non è un nome valido.- Aspettarsi che la DTD controlli date, ordini fra ore o numeri positivi.
- Dimenticare
#REQUIREDo la dichiarazione di un elemento nuovo (nota). - Confondere la scelta
|con la sequenza,.
Versione ripasso
Ben formato. Cinque errori tipici del documento scritto a mano:
- attributo senza virgolette:
id=a1→id="a1"; - tag non corrispondente:
<ora_fine>...</ora_inine>; &nel testo:Rossi & Bianchi;- maiuscole diverse:
<Studente>...</studente>; - due radici: un elemento dopo
</prenotazioni>.
DTD.
<!ELEMENT prenotazioni (aula+, prenotazione*)>
<!ELEMENT aula (nome)>
<!ATTLIST aula id ID #REQUIRED posti CDATA #REQUIRED>
<!ELEMENT prenotazione (giorno, ora_inizio, ora_fine, studente)>
<!ATTLIST prenotazione id ID #REQUIRED aula IDREF #REQUIRED>(più (#PCDATA) per nome, giorno, ora_inizio, ora_fine, studente). La virgola è la sequenza ordinata; + e * sono le cardinalità; ID è unico in tutto il documento ed è un nome XML (a1, p1, non 1); IDREF = riferimento a un ID esistente.
Violazioni di validità (documento ben formato ma non valido):
- manca
posti(#REQUIRED); ora_fineprima diora_inizio(ordine della sequenza);- elemento non dichiarato (
note); IDduplicato (p1due volte);IDREFsenza bersaglio (aula="a9").
La DTD non controlla i valori (giorno accetta qualsiasi testo) né ora_fine > ora_inizio.
Estensione. nota? in coda alla sequenza più <!ELEMENT nota (#PCDATA)>; stato (confermata | annullata) "confermata" = enumerazione con predefinito; stato="sospesa" non è valido.
XML Schema e JSON. xs:time vuole i secondi: si usa una restrizione di xs:string con xs:pattern ([01][0-9]|2[0-3]):[0-5][0-9]. In JSON id e aula_id diventano numeri, attributi ed elementi diventano chiavi uguali (Web service, XML, JSON, SOAP e RESTUn web service e' un servizio software accessibile via rete da altri programmi, con messaggi in formato standard su HTTP; i formati di dati sono XML (marcatori annidati, attributi, namespace, validazione con XSD) e JSON (RFC 8259: oggetti, array, stringhe, numeri, true, false, null; piu' compatto e diretto per i linguaggi di programmazione); SOAP e' un protocollo di messaggi XML (Envelope con Header facoltativo e Body, Fault per gli errori) inviati di solito con una POST HTTP e descritti da un file WSDL; REST e' uno stile architetturale (Fielding) in cui il servizio espone risorse identificate da URI e le manipola con i metodi HTTP: GET legge, POST crea, PUT sostituisce, PATCH modifica, DELETE elimina, con codici di stato significativi (200, 201 con Location, 204, 400, 404, 409), senza stato sul server, con cache e interfaccia uniforme.Web service, XML, JSON, SOAP e REST →).
Errori tipici
- Ben formato scambiato per valido.
IDche comincia con una cifra.- Attendersi controlli sui valori dalla DTD.
- Elemento nuovo non dichiarato. Tabelle di sintesi.
| riga | errore di buona formazione | correzione |
|---|---|---|
| 3 | id=a1 senza virgolette |
id="a1" |
| 7 | </ora_inine> |
</ora_fine> |
| 8 | Rossi & Bianchi |
& |
| 14 | <Studente> con </studente> |
stesse maiuscole |
| 17 | secondo elemento radice | spostarlo dentro la radice |
| riga | violazione della DTD | regola |
|---|---|---|
| 5 | manca posti |
#REQUIRED |
| 17 | ora_fine prima di ora_inizio |
sequenza ordinata |
| 23 | elemento note non dichiarato |
nessun ELEMENT note |
| 25 | id="p1" duplicato |
ID unico |
| 31 | aula="a9" inesistente |
IDREF |
Estensione. <!ELEMENT prenotazione (giorno, ora_inizio, ora_fine, studente, nota?)>, <!ELEMENT nota (#PCDATA)> e stato (confermata | annullata) "confermata" nell'ATTLIST; stato="sospesa" non è valido.
JSON equivalente. {"id": 1, "aula_id": 1, "giorno": "2026-10-19", "ora_inizio": "09:00", "ora_fine": "11:00", "studente": "Rossi"}: i prefissi p e a spariscono e gli identificatori sono numeri.