Ho sempre trovato XML un po 'complicato da elaborare. Non sto parlando dell'implementazione di un parser XML: sto parlando dell'utilizzo di un parser esistente basato su stream, come un parser SAX, che elabora il nodo XML per nodo.
Sì, è davvero facile imparare le varie API per questi parser, ma ogni volta che guardo il codice che elabora XML trovo sempre che sia un po 'contorto. Il problema essenziale sembra essere che un documento XML sia logicamente separato in singoli nodi, eppure i tipi di dati e gli attributi sono spesso separati dai dati reali, a volte da più livelli di annidamento. Pertanto, quando si elabora un determinato nodo singolarmente, è necessario mantenere un sacco di stato extra per determinare dove siamo e cosa dobbiamo fare dopo.
Ad esempio, dato uno snippet da un tipico documento XML:
<book>
<title>Blah blah</title>
<author>Blah blah</author>
<price>15 USD</price>
</book>
... Come determinerei quando ho incontrato un nodo di testo contenente un titolo di libro? Supponiamo di avere un semplice parser XML che agisce come un iteratore, dandoci il nodo successivo nel documento XML ogni volta che chiamiamo XMLParser.getNextNode()
. Mi ritrovo inevitabilmente a scrivere codice come il seguente:
boolean insideBookNode = false;
boolean insideTitleNode = false;
while (!XMLParser.finished())
{
....
XMLNode n = XMLParser.getNextNode();
if (n.type() == XMLTextNode)
{
if (insideBookNode && insideTitleNode)
{
// We have a book title, so do something with it
}
}
else
{
if (n.type() == XMLStartTag)
{
if (n.name().equals("book")) insideBookNode = true
else if (n.name().equals("title")) insideTitleNode = true;
}
else if (n.type() == XMLEndTag)
{
if (n.name().equals("book")) insideBookNode = false;
else if (n.name().equals("title")) insideTitleNode = false;
}
}
}
Fondamentalmente, l'elaborazione XML si trasforma rapidamente in un enorme ciclo guidato da una macchina a stati, con molte variabili di stato utilizzate per indicare nodi padre che abbiamo trovato in precedenza. Altrimenti, è necessario mantenere un oggetto stack per tenere traccia di tutti i tag nidificati. Questo diventa rapidamente soggetto a errori e difficile da mantenere.
Ancora una volta, il problema sembra essere che i dati a cui siamo interessati non siano direttamente associati a un singolo nodo. Certo, potrebbe essere, se abbiamo scritto l'XML come:
<book title="Blah blah" author="blah blah" price="15 USD" />
... ma questo è raramente il modo in cui XML viene utilizzato nella realtà. Principalmente abbiamo nodi di testo come figli di nodi principali e dobbiamo tenere traccia dei nodi principali per determinare a cosa si riferisce un nodo di testo.
Quindi ... sto facendo qualcosa di sbagliato? Esiste un modo migliore? A che punto l'utilizzo di un parser basato su stream XML diventa troppo complicato, quindi diventa necessario un parser DOM completo? Mi piacerebbe sentire da altri programmatori che tipo di idiomi usano durante l'elaborazione di XML con parser basati su stream. L'analisi XML basata su stream deve sempre trasformarsi in un'enorme macchina a stati?