Programmering

Kartlegging av XML til Java, del 1

XML er varmt. Fordi XML er en form for selvbeskrivende data, kan den brukes til å kode rik datamodeller. Det er lett å se XMLs verktøy som et datautvekslingsmedium mellom veldig forskjellige systemer. Data kan lett eksponeres eller publiseres som XML fra alle slags systemer: eldre COBOL-programmer, databaser, C ++ -programmer og så videre.

TEKSTBOKS:

TEXTBOX_HEAD: Kartlegging av XML til Java: Les hele serien!

  • Del 1 - Bruk SAX API for å kartlegge XML-dokumenter til Java-objekter
  • Del 2 - Opprett et klassebibliotek som bruker SAX API til å kartlegge XML-dokumenter til Java-objekter

: END_TEXTBOX

Å bruke XML til å bygge systemer gir imidlertid to utfordringer. For det første, mens generering av XML er en grei prosedyre, er den omvendte operasjonen, ved bruk av XML-data fra et program, ikke. For det andre er nåværende XML-teknologier enkle å misbruke, noe som kan gi en programmerer et sakte, minnehungret system. Faktisk kan tunge minnekrav og lave hastigheter vise seg å være problematiske for systemer som bruker XML som sitt primære datautvekslingsformat.

Noen standardverktøy som for øyeblikket er tilgjengelige for arbeid med XML, er bedre enn andre. Spesielt SAX API har noen viktige kjøretidsfunksjoner for ytelsessensitiv kode. I denne artikkelen vil vi utvikle noen mønstre for å bruke SAX API. Du vil være i stand til å lage rask XML-til-Java-kartleggingskode med et minimum minneavtrykk, selv for ganske komplekse XML-strukturer (med unntak av rekursive strukturer).

I del 2 av denne serien vil vi dekke bruk av SAX API på rekursive XML-strukturer der noen av XML-elementene representerer lister over lister. Vi vil også utvikle et klassebibliotek som styrer navigasjonsaspektene til SAX API. Dette biblioteket forenkler skriving av XML-kartleggingskode basert på SAX.

Kartleggingskode er lik kompileringskode

Å skrive programmer som bruker XML-data er som å skrive en kompilator. Det vil si at de fleste kompilatorer konverterer kildekode til et kjørbart program i tre trinn. Først, a lexer modulen grupperer tegn i ord eller tokens som kompilatoren gjenkjenner - en prosess som kalles tokenisering. En annen modul, kalt parser, analyserer grupper av tokens for å gjenkjenne juridiske språkkonstruksjoner. Sist, en tredje modul, den kode generator, tar et sett med juridiske språkkonstruksjoner og genererer kjørbar kode. Noen ganger blandes parsing og generering av kode.

For å bruke XML-data i et Java-program, må vi gjennomgå en lignende prosess. Først analyserer vi hvert tegn i XML-teksten for å gjenkjenne juridiske XML-tokens som startkoder, attributter, sluttkoder og CDATA-seksjoner.

For det andre verifiserer vi at tokens danner juridiske XML-konstruksjoner. Hvis et XML-dokument utelukkende består av juridiske konstruksjoner i henhold til XML 1.0-spesifikasjonen, er det det velformet. På det mest grunnleggende nivået må vi sørge for at for eksempel alle merkingene har samsvarende åpnings- og lukkekoder, og attributtene er riktig strukturert i åpningskoden.

Også, hvis en DTD er tilgjengelig, har vi muligheten til å sørge for at XML-konstruksjonene som er funnet under parsing, er lovlige når det gjelder DTD, i tillegg til å være velformet XML.

Til slutt bruker vi dataene i XML-dokumentet for å oppnå noe nyttig - jeg kaller denne kartleggingen XML til Java.

XML-parsere

Heldigvis er det hyllekomponenter - XML-parsere - som utfører noen av disse kompilatorrelaterte oppgavene for oss. XML-parsers håndterer alle leksikale analyser og parsingoppgaver for oss. Mange for tiden tilgjengelige Java-baserte XML-parsere støtter to populære parsingsstandarder: SAX og DOM API-er.

Tilgjengeligheten av en XML-parser uten hylle kan gjøre at det virker som om den vanskelige delen av å bruke XML i Java er gjort for deg. I virkeligheten er å bruke en hylle-XML-parser en involvert oppgave.

SAX og DOM APIer

SAX API er hendelsesbasert. XML-parsere som implementerer SAX API, genererer hendelser som tilsvarer forskjellige funksjoner som finnes i det analyserte XML-dokumentet. Ved å svare på denne strømmen av SAX-hendelser i Java-kode, kan du skrive programmer drevet av XML-baserte data.

DOM API er en objektmodellbasert API. XML-parsere som implementerer DOM, lager en generisk objektmodell i minnet som representerer innholdet i XML-dokumentet. Når XML-parseren har fullført parsingen, inneholder minnet et tre med DOM-objekter som gir informasjon om både strukturen og innholdet i XML-dokumentet.

DOM-konseptet vokste ut av HTML-nettleserens verden, der en vanlig dokumentobjektmodell representerer HTML-dokumentet som er lastet inn i nettleseren. Denne HTML DOM blir deretter tilgjengelig for skriptspråk som JavaScript. HTML DOM har vært veldig vellykket i dette programmet.

Farene ved DOM

Ved første øyekast ser DOM API ut til å være mer funksjonsrikt og derfor bedre enn SAX API. DOM har imidlertid alvorlige effektivitetsproblemer som kan skade ytelsesfølsomme applikasjoner.

Den nåværende gruppen av XML-parsere som støtter DOM, implementerer objektmodellen i minnet ved å opprette mange små objekter som representerer DOM-noder som inneholder enten tekst eller andre DOM-noder. Dette høres naturlig nok ut, men har negative ytelsesimplikasjoner. En av de dyreste operasjonene i Java er ny operatør. Tilsvarende for alle ny operatør utført i Java, må JVM søppeloppsamler til slutt fjerne objektet fra minnet når det ikke er noen referanser til objektet. DOM API har en tendens til å virkelig kaste JVM-minnesystemet med sine mange små gjenstander, som vanligvis kastes til side snart etter parsing.

Et annet DOM-problem er det faktum at det laster hele XML-dokumentet i minnet. For store dokumenter blir dette et problem. Igjen, siden DOM er implementert så mange små objekter, er minnefotavtrykket enda større enn selve XML-dokumentet fordi JVM lagrer noen ekstra byte med informasjon om alle disse objektene, så vel som innholdet i XML-dokumentet.

Det er også bekymringsfullt at mange Java-programmer faktisk ikke bruker DOMs generiske objektstruktur. I stedet, så snart DOM-strukturen lastes inn i minnet, kopierer de dataene til en objektmodell som er spesifikk for et bestemt problemdomene - en subtil, men likevel sløsende prosess.

Et annet subtilt problem for DOM API er at koden som er skrevet for den, må skanne XML-dokumentet to ganger. Den første passeringen oppretter DOM-strukturen i minnet, den andre lokaliserer alle XML-data programmet er interessert i. Visse kodestiler kan krysse DOM-strukturen flere ganger mens de finner forskjellige deler av XML-data. Derimot oppfordrer SAXs kodestil til å finne og samle XML-data i ett enkelt pass.

Noen av disse problemene kan løses med en bedre underliggende datastrukturdesign for å representere DOM-objektmodellen internt. Problemer som å oppmuntre til flere prosesseringskort og oversettelse mellom generiske og spesifikke objektmodeller kan ikke tas opp i XML-parsers.

SAX for overlevelse

Sammenlignet med DOM API er SAX API en attraktiv tilnærming. SAX har ikke en generisk objektmodell, så den har ikke hukommelses- eller ytelsesproblemer knyttet til misbruk av ny operatør. Og med SAX er det ingen generisk objektmodell å ignorere hvis du planlegger å bruke en bestemt problem-domene objektmodell i stedet. Siden SAX behandler XML-dokumentet i ett pass, krever det dessuten mye mindre behandlingstid.

SAX har noen ulemper, men de er hovedsakelig relatert til programmereren, ikke ytelsen til API-en. La oss se på noen få.

Den første ulempen er konseptuell. Programmerere er vant til å navigere for å få data; for å finne en fil på en filserver, navigerer du ved å endre kataloger. På samme måte, for å få data fra en database, skriver du en SQL-spørring for dataene du trenger. Med SAX er denne modellen invertert. Det vil si at du setter opp kode som lytter til listen over alle tilgjengelige tilgjengelige XML-data. Denne koden aktiveres bare når interessante XML-data blir oppført. Først virker SAX API merkelig, men etter en stund blir det å tenke på denne omvendte måten andre natur.

Den andre ulempen er farligere. Med SAX-kode vil den naive tilnærmingen "la oss ta et hack på det" slå tilbake ganske raskt, fordi SAX-parseren navigerer uttømmende i XML-strukturen samtidig som den leverer data lagret i XML-dokumentet. De fleste mennesker fokuserer på datakartingsaspektet og forsømmer navigasjonsaspektet. Hvis du ikke direkte adresserer navigasjonsaspektet ved SAX-parsing, vil koden som holder oversikt over plasseringen i XML-strukturen under SAX-parsing bli spredt og ha mange subtile interaksjoner. Dette problemet ligner de som er forbundet med overdreven avhengighet av globale variabler. Men hvis du lærer deg å strukturere SAX-koden riktig for å forhindre at den blir uhåndterlig, er den enklere enn å bruke DOM API.

Grunnleggende SAX

Det er for tiden to publiserte versjoner av SAX API. Vi bruker versjon 2 (se Ressurser) for eksemplene våre. Versjon 2 bruker forskjellige klasse- og metodenavn enn versjon 1, men strukturen til koden er den samme.

SAX er en API, ikke en parser, så denne koden er generisk på tvers av XML-parsere. For å få eksemplene til å kjøre, må du få tilgang til en XML-parser som støtter SAX v2. Jeg bruker Apache's Xerces parser. (Se ressurser.) Gjennomgå parserens startveiledning for å få detaljer om å påkalle en SAX-parser.

SAX API-spesifikasjonen er ganske grei. In inkluderer mange detaljer, men hovedoppgaven er å lage en klasse som implementerer ContentHandler grensesnitt, et tilbakeringingsgrensesnitt som brukes av XML-parsere for å varsle programmet om SAX-hendelser slik de finnes i XML-dokumentet.

SAX API leverer også praktisk en DefaultHandler implementeringsklasse for ContentHandler grensesnitt.

Når du har implementert ContentHandler eller utvidet DefaultHandler, trenger du bare å lede XML-parseren for å analysere et bestemt dokument.

Vårt første eksempel utvider DefaultHandler for å skrive ut hver SAX-hendelse til konsollen. Dette vil gi deg en følelse av hvilke SAX-hendelser som genereres og i hvilken rekkefølge.

For å komme i gang, her er eksemplet på XML-dokumentet vi vil bruke i vårt første eksempel:

   Bob New York 

Deretter ser vi kildekoden for XML-kartleggingskode for det første eksemplet:

importer org.xml.sax. *; importer org.xml.sax.helpers. *; importer java.io. *; offentlig klasse Eksempel1 utvider DefaultHandler {// Overstyr metodene til StandardHandler-klassen // for å få varsel om SAX-hendelser. // // Se org.xml.sax.ContentHandler for alle tilgjengelige arrangementer. // public void startDocument () kaster SAXException {System.out.println ("SAX Event: START DOCUMENT"); } public void endDocument () kaster SAXException {System.out.println ("SAX Event: END DOCUMENT"); } public void startElement (String namespaceURI, String localName, String qName, Attributts attr) kaster SAXException {System.out.println ("SAX Event: START ELEMENT [" + localName + "]"); // La oss også skrive ut attributtene hvis // det er noen ... for (int i = 0; i <attr.getLength (); i ++) {System.out.println ("ATTRIBUTE:" + attr.getLocalName ( i) + "VERDI:" + attr.getValue (i)); }} public void endElement (String namespaceURI, String localName, String qName) kaster SAXException {System.out.println ("SAX Event: END ELEMENT [" + localName + "]"); } offentlige ugyldige tegn (char [] ch, int start, int lengde) kaster SAXException {System.out.print ("SAX Event: CHARACTERS ["); prøv {OutputStreamWriter outw = ny OutputStreamWriter (System.out); outw.write (ch, start, lengde); outw.flush (); } fange (Unntak e) {e.printStackTrace (); } System.out.println ("]"); } public static void main (String [] argv) {System.out.println ("Eksempel1 SAX-hendelser:"); prøv {// Opprett SAX 2-parser ... XMLReader xr = XMLReaderFactory.createXMLReader (); // Still inn ContentHandler ... xr.setContentHandler (nytt eksempel1 ()); // Parse filen ... xr.parse (ny InputSource (ny FileReader ("Eksempel1.xml")); } fange (Unntak e) {e.printStackTrace (); }}} 

Til slutt, her er utdata generert ved å kjøre det første eksemplet med XML-dokumentet vårt:

Eksempel1 SAX hendelser: SAX hendelse: START DOKUMENT SAX hendelse: START ELEMENT [enkel] ATTRIBUTE: dato VERDI: 7/7/2000 SAX hendelse: KARAKTERER [] SAX hendelse: START ELEMENT [navn] SAX hendelse: KARAKTERER [Bob] SAX hendelse : END ELEMENT [navn] SAX hendelse: KARAKTERER [] SAX hendelse: START ELEMENT [sted] SAX hendelse: KARAKTERER [New York] SAX hendelse: SLUT ELEMENT [plassering] SAX hendelse: KARAKTERER [] SAX hendelse: SLUT ELEMENT [enkel] SAX-begivenhet: SLUTDOKUMENT 

Som du kan se, vil SAX-parseren kalle det aktuelle ContentHandler metode for hver SAX-hendelse den oppdager i XML-dokumentet.

Hei Verden

Nå som vi forstår det grunnleggende mønsteret til SAX, kan vi begynne å gjøre noe litt nyttig: trekke ut verdier fra vårt enkle XML-dokument og demonstrere det klassiske hei-verdensprogrammet.

$config[zx-auto] not found$config[zx-overlay] not found