Salta al contenuto
Note per Studenti Esercizio - XML ben formato e valido con una DTD per le prenotazioni (applicazione web)

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
<?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 &amp; Rossi &amp; 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'aula ha un attributo id (identificatore unico, obbligatorio), un attributo posti (obbligatorio) e un figlio nome di testo;
  • una prenotazione ha un attributo id (identificatore unico, obbligatorio), un attributo aula che 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.

dtd
<!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 un ID esistente. posti è CDATA (testo qualsiasi: la DTD non ha il tipo numero).
  • Perché a1 e non 1? Un valore di tipo ID è 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 stesso id, e un documento con id="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 di giorno, ora_inizio, ora_fine, studente ci 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
<?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 giorno sia una data o che ora_fine sia dopo ora_inizio (nella prenotazione p3, 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.

dtd
<!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'elemento nota.
  • stato (confermata | annullata) "confermata": un'enumerazione con valore predefinito: se l'attributo manca, il parser validante lo considera confermata. Con stato="sospesa" il documento non è valido (verificato: Attribute "stato" with value "sospesa" must have a value from the list "confermata annullata"); il documento con stato="annullata" e una nota è valido.
  • Il vecchio documento resta valido: nota è facoltativa e stato ha 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:

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

json
{"id": 1, "aula_id": 1, "giorno": "2026-10-19", "ora_inizio": "09:00", "ora_fine": "11:00", "studente": "Rossi"}

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 un ID: non è un nome valido.
  • Aspettarsi che la DTD controlli date, ordini fra ore o numeri positivi.
  • Dimenticare #REQUIRED o 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 &amp; Bianchi;
  • maiuscole diverse: <Studente>...</studente>;
  • due radici: un elemento dopo </prenotazioni>.

Il parser XML si ferma al primo errore (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 →).

DTD.

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_fine prima di ora_inizio (ordine della sequenza);
  • elemento non dichiarato (note);
  • ID duplicato (p1 due volte);
  • IDREF senza 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.
  • ID che 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 &amp;
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.

Teoria collegata