Una sezione CDATA (acronimo di Character Data) è un costrutto definito dalla specifica W3C XML 1.0 §2.7 che permette di includere in un documento XML blocchi di testo contenenti caratteri riservati (<, >, &) senza che il parser li interpreti come markup. È un artefatto di sintassi, non di semantica: il contenuto di una sezione CDATA e il testo equivalente espresso con entity reference producono lo stesso XML Information Set, cioè lo stesso albero logico per il parser.
Cosa significa CDATA (Character Data)
CDATA sta per Character Data: dati carattere. In una sezione CDATA il parser XML interpreta ogni sequenza come testo letterale, senza riconoscere markup, entity reference o processing instruction. L’unica sequenza che ha significato speciale è la chiusura ]]>, che non può mai apparire all’interno della sezione.
È importante distinguere due piani:
- Piano sintattico: CDATA è una scorciatoia di scrittura che evita di dover scrivere
<al posto di<e&al posto di&. - Piano semantico: il contenuto di una sezione CDATA è indistinguibile dal testo equivalente con entity reference. Dopo il parsing le due forme sono equivalenti e un’applicazione che legge l’XML tramite DOM o SAX non può nemmeno sapere se il dato originale era in CDATA o no (tranne con API specifiche come
LexicalHandlerin Java).
Sintassi di una sezione CDATA
La sintassi è rigida e case-sensitive. Apertura con <![CDATA[ e chiusura con ]]>:
<![CDATA[
testo libero con caratteri < > & senza escape
]]>
Esempio completo dentro un documento XML ben formato:
<?xml version="1.0" encoding="UTF-8"?>
<script>
<![CDATA[
if (a < b && c > d) {
return "a minore di b e c maggiore di d";
}
]]>
</script>
Senza CDATA lo stesso contenuto richiederebbe l’escape esplicito di tre caratteri:
<script>
if (a < b && c > d) {
return "a minore di b e c maggiore di d";
}
</script>
Le due forme sono equivalenti per il parser, ma la prima è più leggibile quando il payload contiene molti caratteri riservati (codice, HTML, espressioni regolari).
PCDATA vs CDATA: come i parser le distinguono
La distinzione tra PCDATA e CDATA è una delle più confuse nella letteratura XML, perché il termine CDATA appare in due contesti diversi:
- PCDATA (Parsed Character Data) — il testo normale di un elemento, che viene analizzato dal parser: entity reference come
&vengono risolte, tag vengono riconosciuti. È la modalità di default per il contenuto di ogni elemento. - CDATA section (
<![CDATA[ ... ]]>) — un blocco in cui il parser sospende l’interpretazione e tratta tutto come testo letterale. - CDATA attribute type — nelle DTD,
CDATAè anche il tipo più generico che un attributo può assumere (es.<!ATTLIST img src CDATA #REQUIRED>). Non va confuso con le sezioni CDATA: qui significa semplicemente “stringa di caratteri”.
Quando si cerca su Google “cdata dtd” o “cdata element” si sta quasi sempre parlando del tipo di attributo definito in DTD, non delle sezioni. Sono due concetti disgiunti che condividono il nome per ragioni storiche della specifica SGML da cui XML deriva.
Quando usare CDATA: casi d’uso concreti
Le sezioni CDATA risolvono un problema molto specifico: inserire grandi blocchi di testo contenenti caratteri riservati XML senza inquinare la leggibilità con decine di entity reference. I casi d’uso dove conviene davvero usarle sono pochi ma ricorrenti.
Feed RSS e Atom con HTML nel description
Il caso d’uso più comune in ambito SEO. I feed RSS 2.0 usano CDATA nell’elemento <description> per veicolare HTML senza doverlo escapare:
<item>
<title>Guida all'analisi dei log server</title>
<link>https://www.evemilano.com/blog/analisi-log/</link>
<description><![CDATA[
<p>In questo articolo analizziamo <strong>pattern di crawling</strong>
di Googlebot usando <a href="https://www.python.org/">Python</a>.</p>
]]></description>
</item>
Il feed Atom (RFC 4287) ha invece una soluzione più pulita: l’attributo type="html" o type="xhtml" sull’elemento <content>. Molti generatori di feed usano comunque CDATA anche in Atom per compatibilità con i reader che applicano euristiche di parsing.
SOAP envelope, WSDL e file di configurazione
Nei web service SOAP è frequente trovare CDATA quando il body di un messaggio contiene payload eterogenei: XML serializzato, JSON, query SQL, espressioni XPath. Allo stesso modo i file di configurazione di molti tool (Log4j, Ant, Maven plugin) usano CDATA per i pattern di log o gli script inline:
<PatternLayout>
<Pattern><![CDATA[%d{ISO8601} [%t] %-5p %c & %m%n]]></Pattern>
</PatternLayout>
XSLT, MathML e snippet di codice
Gli stylesheet XSLT usano CDATA per includere JavaScript o codice destinato all’output senza escape manuale. Stesso discorso per documenti tecnici che contengono esempi di codice: una sezione CDATA evita di dover escapare ogni minore/maggiore.
Regole e limitazioni di una sezione CDATA
Le regole imposte dalla specifica XML 1.0 sono quattro e sono tutte verificate dal parser in fase di validazione:
- Non sono annidabili. Non è possibile scrivere
<![CDATA[ ... <![CDATA[ ... ]]> ... ]]>: la prima occorrenza di]]>chiude la sezione. - La sequenza
]]>non può apparire nel contenuto. Per inserirla letteralmente va spezzata in due sezioni contigue oppure sostituendo>con>. - Le entity reference non vengono risolte. All’interno di CDATA,
&è la stringa letterale di cinque caratteri, non la e commerciale. - Possono apparire solo nel content di un elemento, mai negli attributi, nel prolog o nei commenti.
Una limitazione meno nota: una sezione CDATA non è un nodo di tipo Element nel DOM, ma un nodo di tipo CDATASection (che eredita da Text). Molte API di alto livello lo espongono come semplice testo, perdendo l’informazione sulla forma originale.
CDATA nelle sitemap XML: serve davvero?
La domanda arriva spesso durante gli audit tecnici: “la mia sitemap.xml contiene CDATA, devo rimuoverlo?”. La risposta breve è no, non cambia nulla, ma vale la pena spiegare perché.
Il protocollo sitemaps.org definisce sette campi (loc, lastmod, changefreq, priority, alternate, image, video), tutti con contenuto semplice. Alcuni plugin avvolgono il valore di loc in CDATA per cautela, tipicamente per gestire URL con caratteri speciali non correttamente URL-encoded. Esempio:
<url>
<loc><![CDATA[https://www.esempio.com/prodotto?id=42&ref=home]]></loc>
<lastmod>2026-04-22</lastmod>
</url>
Googlebot e Bingbot processano entrambe le forme in modo identico. Non esiste alcun impatto SEO (positivo o negativo) dovuto alla presenza di CDATA in una sitemap. L’unica vera best practice è assicurarsi che gli URL siano URL-encoded secondo RFC 3986: a quel punto il CDATA diventa superfluo.
CDATA vs entity reference: quale scegliere
La scelta è puramente una questione di leggibilità e di tooling:
- Pochi caratteri da escapare (1-3 occorrenze) → entity reference. Mantiene il documento omogeneo e riduce la superficie di errori di chiusura.
- Blocco di testo lungo con molti caratteri riservati (HTML nel feed, snippet di codice, query SQL) → CDATA. Migliora drasticamente la leggibilità.
- Contenuto generato da template engine → quasi sempre entity reference, perché il template esegue automaticamente l’escape del testo in output.
- Contenuto binario → nessuna delle due. Il binario va base64-encoded, non inserito in CDATA.
Un’altra considerazione pratica: alcuni parser XML meno rigorosi o XSLT processor trattano i contenuti CDATA in modo leggermente diverso quando si applica xsl:value-of disable-output-escaping. In pipeline di trasformazione complesse è utile saperlo.
CDATA in HTML5: perché non si usa più
Nell’HTML serializzato (text/html) le sezioni CDATA non esistono. Il parser HTML5 ignora la sintassi <![CDATA[ ... ]]> e la trasforma in un commento bogus. Questo è un cambio rispetto a XHTML, dove il CDATA era legale perché XHTML è XML.
L’HTML5 Living Standard definisce due contesti in cui il parser HTML si comporta come se fosse una sezione CDATA, ma senza la sintassi esplicita:
- Contenuto di
<script>e<style>— il parser non interpreta il markup al loro interno. - Contenuto di elementi MathML e SVG inline — qui la sintassi
<![CDATA[ ... ]]>è consentita perché questi subset sono parsati in foreign content mode, che rispetta le regole XML.
In pratica: su una pagina HTML5 standard, mettere <![CDATA[ dentro uno <script> è un retaggio XHTML che oggi non serve più. La pagina continua a funzionare, ma quei sette caratteri finiscono nell’output come commento ignorato.
Commenti XML vs sezione CDATA
Commenti e sezioni CDATA sono spesso confusi perché entrambi “sospendono” qualcosa, ma hanno scopi opposti:
- Commento XML (
<!-- ... -->): il parser ignora il contenuto. Non finisce nel DOM come dato, è visibile solo con API lessicali. Serve per annotare il sorgente. - Sezione CDATA (
<![CDATA[ ... ]]>): il parser include il contenuto come testo, ma senza interpretarlo come markup. Serve per veicolare dati.
Un commento XML non può contenere la sequenza -- al suo interno, esattamente come una sezione CDATA non può contenere ]]>. Entrambe le limitazioni esistono per garantire che il parser possa sempre riconoscere il terminatore senza ambiguità.
Errori comuni e troubleshooting del parser
Gli errori di parsing legati a CDATA sono ricorrenti e quasi sempre riconducibili a pochi pattern. Riporto quelli che emergono più di frequente durante audit di feed e sitemap:
- Chiusura prematura: il contenuto contiene la sequenza
]]>. Errore tipico quando si inserisce codice XML generato da un altro processo senza sanitizzare. - Case sensitivity:
<![cdata[ ... ]]>in minuscolo non è valido. La parola chiaveCDATAdeve essere sempre in maiuscolo. - Spazi nell’apertura:
<! [CDATA[con spazio tra<!e[CDATA[produce errore di parsing. - Encoding mismatch: se il documento dichiara
UTF-8ma il contenuto CDATA contiene byte non validi UTF-8 (tipico con database legacy in Latin-1), il parser fallisce con not well-formed. - BOM invisibile: un Byte Order Mark all’interno del CDATA viene preservato come carattere testuale e può rompere il consumer downstream.
Per validare una sezione CDATA in Python basta xml.etree.ElementTree o lxml: se il parser non solleva eccezioni, la sezione è ben formata. Un esempio di parsing con logging degli errori:
from lxml import etree
parser = etree.XMLParser(strip_cdata=False, recover=False)
try:
tree = etree.parse("feed.xml", parser)
root = tree.getroot()
for item in root.iter("item"):
desc = item.findtext("description")
print(desc[:80])
except etree.XMLSyntaxError as e:
print(f"XML non ben formato: {e}")
Il flag strip_cdata=False è essenziale se si vuole preservare la forma originale del documento; con il default True, lxml fonde automaticamente CDATA e testo normale.
FAQ su CDATA in XML
Cosa significa esattamente ]]>?
È la sequenza di chiusura obbligatoria di una sezione CDATA. Tre caratteri: due parentesi quadre chiuse seguite dal simbolo maggiore. Non esiste modo di “escapare” questa sequenza dentro la sezione stessa: se serve, va spezzata in due sezioni CDATA contigue.
Si possono annidare due sezioni CDATA?
No. La prima ]]> chiude sempre la sezione, indipendentemente dalla struttura attesa. Se serve includere codice che a sua volta contiene <![CDATA[, va inserito letteralmente perché dentro CDATA non viene riconosciuto come markup.
CDATA e JSON: esiste un equivalente?
No. JSON non ha caratteri riservati strutturali a parte " e \, che si escapano con backslash. Il problema che CDATA risolve non esiste in JSON.
CDATA impatta la SEO del feed RSS o della sitemap?
No. Googlebot processa in modo identico il contenuto CDATA e il contenuto con entity reference. L’impatto è esclusivamente sulla leggibilità e sulla manutenibilità del sorgente XML.
Autore
Mi chiamo Giovanni Sacheli e dal 2009 aiuto le aziende a farsi trovare online. Sono specializzato in SEO tecnica e PPC, competenze che applico quotidianamente nella mia agenzia, Searcus Swiss Sagl. Mi piace sviluppare strumenti a supporto del mio lavoro, ho creato SEOdata.app e cluster.army e co-scritto il libro SEO Audit Avanzato. Curo maniacalmente questo blog per colleghi e appassionati, dove mi "appunto" quello che imparo. Sono un NERD anni '80, motociclista e orgoglioso papà di due bambini.
Link:
Giovanni Sacheli
SEO Audit Avanzato
Searcus Swiss Sagl
SEOdata.app
cluster.army