Analisi di un file XML utilizzando SAX Parser

1. Panoramica

SAX, noto anche come API semplice per XML , viene utilizzato per analizzare i documenti XML.

In questo tutorial impareremo cos'è SAX e perché, quando e come dovrebbe essere utilizzato.

2. SAX : l'API semplice per XML

SAX è un'API utilizzata per analizzare i documenti XML. Si basa sugli eventi generati durante la lettura del documento. I metodi di callback ricevono questi eventi. Un gestore personalizzato contiene questi metodi di callback.

L'API è efficiente perché rilascia gli eventi subito dopo che i callback li hanno ricevuti. Pertanto, SAX ha una gestione efficiente della memoria , a differenza di DOM, ad esempio.

3. SAX vs DOM

DOM sta per Document Object Model. Il parser DOM non si basa sugli eventi . Inoltre, carica l'intero documento XML in memoria per analizzarlo. SAX è più efficiente in termini di memoria di DOM.

Anche DOM ha i suoi vantaggi. Ad esempio, DOM supporta XPath. Rende inoltre facile operare contemporaneamente sull'intero albero del documento poiché il documento viene caricato in memoria .

4. SAX vs StAX

StAX è più recente di SAX e DOM. Sta per Streaming API for XML .

La differenza principale con SAX è che StAX utilizza un meccanismo di pull invece del meccanismo di push di SAX (utilizzando i callback).

Ciò significa che il controllo è dato al client per decidere quando gli eventi devono essere tirati. Pertanto, non vi è alcun obbligo di estrarre l'intero documento se è necessaria solo una parte di esso.

Fornisce un'API semplice per lavorare con XML con un modo di analisi efficiente in termini di memoria.

A differenza di SAX, non fornisce la convalida dello schema come una delle sue caratteristiche.

5. Analisi del file XML utilizzando un gestore personalizzato

Usiamo ora il seguente XML che rappresenta il sito web di Baeldung e i suoi articoli:

   Parsing an XML File Using SAX Parser SAX Parser's Lorem ipsum...   Parsing an XML File Using DOM Parser DOM Parser's Lorem ipsum...   Parsing an XML File Using StAX Parser StAX's Lorem ipsum...   

Inizieremo creando POJO per il nostro elemento radice Baeldung e i suoi figli:

public class Baeldung { private List articleList; // usual getters and setters } 
public class BaeldungArticle { private String title; private String content; // usual getters and setters } 

Continueremo creando BaeldungHandler . Questa classe implementerà i metodi di callback necessari per acquisire gli eventi.

Sostituiremo quattro metodi dalla superclasse DefaultHandler, ognuno caratterizzante un evento:

    • caratteri (char [], int, int) riceve caratteri con confini. Li convertiremo in una stringa e lo memorizzeremo in una variabile di BaeldungHandler
    • startDocument () viene invocato quando inizia l'analisi: lo useremo per costruire la nostra istanza di Baeldung
    • startElement () viene invocato quando inizia l'analisi per un elemento - lo useremo per costruire istanze List o BaeldungArticle - qName ci aiuta a fare la distinzione tra entrambi i tipi
    • endElement () viene invocato quando il parsing termina per un elemento - questo è il momento in cui assegneremo il contenuto dei tag alle rispettive variabili

Con tutti i callback definiti, ora possiamo scrivere la classe BaeldungHandler :

public class BaeldungHandler extends DefaultHandler { private static final String ARTICLES = "articles"; private static final String ARTICLE = "article"; private static final String TITLE = "title"; private static final String CONTENT = "content"; private Baeldung website; private String elementValue; @Override public void characters(char[] ch, int start, int length) throws SAXException { elementValue = new String(ch, start, length); } @Override public void startDocument() throws SAXException { website = new Baeldung(); } @Override public void startElement(String uri, String lName, String qName, Attributes attr) throws SAXException { switch (qName) { case ARTICLES: website.articleList = new ArrayList(); break; case ARTICLE: website.articleList.add(new BaeldungArticle()); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { switch (qName) { case TITLE: latestArticle().title = elementValue; break; case CONTENT: latestArticle().content = elementValue; break; } } private BaeldungArticle latestArticle() { List articleList = website.articleList; int latestArticleIndex = articleList.size() - 1; return articleList.get(latestArticleIndex); } public Baeldung getWebsite() { return website; } } 

Sono state aggiunte anche costanti di stringa per aumentare la leggibilità. È anche conveniente un metodo per recuperare l'ultimo articolo incontrato. Infine, abbiamo bisogno di un getter per l' oggetto Baeldung .

Nota che quanto sopra non è thread-safe poiché stiamo mantenendo lo stato tra le chiamate al metodo.

6. Test del parser

Per testare il parser, istanzeremo SaxFactory , SaxParser e anche BaeldungHandler :

SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser saxParser = factory.newSAXParser(); SaxParserMain.BaeldungHandler baeldungHandler = new SaxParserMain.BaeldungHandler(); 

Successivamente, analizzeremo il file XML e asseriremo che l'oggetto contiene tutti gli elementi previsti analizzati:

saxParser.parse("src/test/resources/sax/baeldung.xml", baeldungHandler); SaxParserMain.Baeldung result = baeldungHandler.getWebsite(); assertNotNull(result); List articles = result.getArticleList(); assertNotNull(articles); assertEquals(3, articles.size()); SaxParserMain.BaeldungArticle articleOne = articles.get(0); assertEquals("Parsing an XML File Using SAX Parser", articleOne.getTitle()); assertEquals("SAX Parser's Lorem ipsum...", articleOne.getContent()); SaxParserMain.BaeldungArticle articleTwo = articles.get(1); assertEquals("Parsing an XML File Using DOM Parser", articleTwo.getTitle()); assertEquals("DOM Parser's Lorem ipsum...", articleTwo.getContent()); SaxParserMain.BaeldungArticle articleThree = articles.get(2); assertEquals("Parsing an XML File Using StAX Parser", articleThree.getTitle()); assertEquals("StAX Parser's Lorem ipsum...", articleThree.getContent()); 

Come previsto, il baeldung è stato analizzato correttamente e contiene gli oggetti secondari attesi.

7. Conclusione

Abbiamo appena scoperto come utilizzare SAX per analizzare i file XML. È una potente API che genera un leggero footprint di memoria nelle nostre applicazioni.

Come al solito, il codice per questo articolo è disponibile su GitHub.