Java >> Java tutorial >  >> Tag >> XML

Parsing af en XML-fil ved hjælp af SAX Parser

1. Oversigt

SAX, også kendt som den simple API til XML , bruges til at parse XML-dokumenter.

I denne vejledning lærer vi, hvad SAX er, og hvorfor, hvornår og hvordan det skal bruges.

2. SAX :Simple API til XML

SAX er et API, der bruges til at parse XML-dokumenter. Det er baseret på begivenheder genereret under gennemlæsning af dokumentet. Tilbagekaldsmetoder modtager disse begivenheder. En brugerdefineret handler indeholder disse tilbagekaldsmetoder.

API'en er effektiv, fordi den dropper hændelser lige efter tilbagekaldene har modtaget dem. Derfor har SAX effektiv hukommelsesstyring , i modsætning til f.eks. DOM.

3. SAX vs DOM

DOM står for Document Object Model. DOM-parseren er ikke afhængig af hændelser . Desuden indlæser den hele XML-dokumentet i hukommelsen for at parse det. SAX er mere hukommelseseffektiv end DOM.

DOM har også sine fordele. For eksempel understøtter DOM XPath. Det gør det også nemt at betjene hele dokumenttræet på én gang, da dokumentet er indlæst i hukommelsen .

4. SAX vs StAX

StAX er nyere end SAX og DOM. Det står for Streaming API for XML .

Den største forskel med SAX er, at StAX bruger en trækmekanisme i stedet for SAX's push-mekanisme (ved hjælp af tilbagekald).
Det betyder, at kontrollen er givet til klienten for at bestemme, hvornår begivenhederne skal trækkes. Derfor er der ingen forpligtelse til at trække hele dokumentet, hvis kun en del af det er nødvendigt.

Det giver en nem API til at arbejde med XML med en hukommelseseffektiv måde at parse på.

I modsætning til SAX giver den ikke skemavalidering som en af ​​dens funktioner.

5. Parsing af XML-filen ved hjælp af en brugerdefineret handler

Lad os nu bruge følgende XML, der repræsenterer Baeldungs ​​websted og dets artikler:

<baeldung>
    <articles>
        <article>
            <title>Parsing an XML File Using SAX Parser</title>
            <content>SAX Parser's Lorem ipsum...</content>
        </article>
        <article>
            <title>Parsing an XML File Using DOM Parser</title>
            <content>DOM Parser's Lorem ipsum...</content>
        </article>
        <article>
            <title>Parsing an XML File Using StAX Parser</title>
            <content>StAX's Lorem ipsum...</content>
        </article>
    </articles>
</baeldung>

Vi begynder med at oprette POJO'er til vores Baeldung rodelement og dets børn:

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

Vi fortsætter med at oprette BaeldungHandler . Denne klasse implementerer de callback-metoder, der er nødvendige for at fange begivenhederne.

Vi tilsidesætter fire metoder fra superklassen DefaultHandler,  hver karakteriserer en begivenhed:

    • tegn(tegn[], int, int) modtager tegn med grænser. Vi konverterer dem til en streng og gem det i en variabel BaeldungHandler
    • startDocument() påkaldes, når parsingen begynder – vi bruger den til at konstruere vores Baeldung forekomst
    • startElement() påkaldes, når parsingen begynder for et element – ​​vi bruger det til at konstruere enten List eller BaeldungArticle forekomster – qName hjælper os med at skelne mellem begge typer
    • endElement() påkaldes, når parsingen slutter for et element – ​​det er her, vi tildeler indholdet af taggene til deres respektive variable

Med alle tilbagekald defineret, kan vi nu skrive BaeldungHandler klasse:

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 StringBuilder elementValue;

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        if (elementValue == null) {
            elementValue = new StringBuilder();
        } else {
            elementValue.append(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());
                break;
            case TITLE:
                elementValue = new StringBuilder();
                break;
            case CONTENT:
                elementValue = new StringBuilder();
                break;
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        switch (qName) {
            case TITLE:
                latestArticle().setTitle(elementValue.toString());
                break;
            case CONTENT:
                latestArticle().setContent(elementValue.toString());
                break;
        }
    }

    private BaeldungArticle latestArticle() {
        List<BaeldungArticle> articleList = website.articleList;
        int latestArticleIndex = articleList.size() - 1;
        return articleList.get(latestArticleIndex);
    }

    public Baeldung getWebsite() {
        return website;
    }
}

Strengkonstanter er også blevet tilføjet for at øge læsbarheden. En metode til at hente den seneste genstand er også praktisk. Endelig har vi brug for en getter til Baeldung objekt.

Bemærk, at ovenstående ikke er trådsikkert, da vi holder på staten mellem metodekaldene.

6. Test af parseren

For at teste parseren instansierer vi SaxFactory , SaxParser og også BaeldungHandler :

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

Derefter parser vi XML-filen og hævder, at objektet indeholder alle forventede elementer, der er parset:

saxParser.parse("src/test/resources/sax/baeldung.xml", baeldungHandler);

SaxParserMain.Baeldung result = baeldungHandler.getWebsite();

assertNotNull(result);
List<SaxParserMain.BaeldungArticle> 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());

Som forventet er baeldung er blevet analyseret korrekt og indeholder de ventede underobjekter.

7. Konklusion

Vi har lige opdaget, hvordan man bruger SAX til at parse XML-filer. Det er en kraftfuld API, der genererer et let hukommelsesfodaftryk i vores applikationer.

Som sædvanlig er koden til denne artikel tilgængelig på GitHub.


Java tag