Programmering

Programmering av XML i Java, del 1

Så du forstår (mer eller mindre) hvordan du vil representere dataene dine i XML, og du er interessert i å bruke XML til å løse mange av datahåndteringsproblemene dine. Likevel er du ikke sikker på hvordan du bruker XML med Java-programmene dine.

TEXTBOX: TEXTBOX_HEAD: Programmering av XML i Java: Les hele serien!

  • Del 1. Bruk Simple API for XML (SAX) til å behandle XML i Java enkelt
  • Del 2. Lær om SAX- og XML-validering gjennom illustrerende eksempler
  • Del 3. DOMINASJON: Ta kontroll over strukturerte dokumenter med Document Object Model

: END_TEXTBOX

Denne artikkelen er en oppfølging av min innledende artikkel, "XML for den absolutte nybegynneren", i april 1999-utgaven av JavaWorld (se URL-delen nedenfor for URL). Den artikkelen beskrev XML; Jeg vil nå bygge videre på den beskrivelsen og vise i detalj hvordan jeg lager et program som bruker Simple API for Java (SAX), en lett og kraftig standard Java API for behandling av XML.

Eksempelkoden som brukes her, bruker SAX API for å lese en XML-fil og lage en nyttig struktur for objekter. Når du er ferdig med denne artikkelen, er du klar til å lage dine egne XML-baserte applikasjoner.

Dyden til latskap

Larry Wall, gal geni-skaper av Perl (det nest største programmeringsspråket som eksisterer), har uttalt at latskap er en av de "tre store dyder" til en programmerer (de to andre er utålmodighet og hubris). Latskap er en dyd fordi en lat programmerer vil gå i nesten alle lengder for å unngå arbeid, til og med gå så langt som å lage generelle, gjenbrukbare programmeringsrammer som kan brukes gjentatte ganger. Å lage slike rammer innebærer mye arbeid, men tiden som spares på fremtidige oppgaver, kompenserer mer enn den første innsatsen som ble investert. De beste rammene lar programmerere gjøre fantastiske ting med lite eller ingen arbeid - og det er derfor latskap er dydig.

XML er en aktiveringsteknologi for den dydige (late) programmereren. En grunnleggende XML-parser gjør mye arbeid for programmereren, gjenkjenne tokens, oversette kodede tegn, håndheve regler for XML-filstruktur, kontrollere gyldigheten av noen dataværdier, og ringe til applikasjonsspesifikk kode, der det er aktuelt. Tidlig standardisering, kombinert med et sterkt konkurransedyktig marked, har faktisk gitt mange poeng fritt tilgjengelige implementeringer av standard XML-parsere på mange språk, inkludert C, C ++, Tcl, Perl, Python og, selvfølgelig, Java.

SAX API er et av de enkleste og letteste grensesnittene for håndtering av XML. I denne artikkelen vil jeg bruke IBMs XML4J-implementering av SAX, men siden API er standardisert, kan applikasjonen din erstatte enhver pakke som implementerer SAX.

SAX er et hendelsesbasert API som fungerer etter tilbakeringingsprinsippet. En applikasjonsprogrammerer vil vanligvis opprette en SAX Parser objektet, og send det både input XML og a dokumentbehandler, som mottar tilbakeringinger for SAX-hendelser. SAX Parser konverterer sine innspill til en strøm av arrangementer tilsvarer strukturelle trekk ved inngangen, for eksempel XML-koder eller tekstblokker. Når hver hendelse inntreffer, overføres den til den riktige metoden til en programmererdefinert dokumentbehandler, som implementerer tilbakeringingsgrensesnittet org.xml.sax.DocumentHandler. Metodene i denne håndteringsklassen utfører den applikasjonsspesifikke funksjonaliteten under analysen.

Tenk deg for eksempel at en SAX-parser mottar et dokument som inneholder det lille XML-dokumentet som vises i liste 1 nedenfor. (Se ressurser for XML-filen.)

 Ogden Nash Fleas Adam Had 'em. 

Oppføring 1. XML som representerer et kort dikt

Når SAX-parseren møter koden, kaller den den brukerdefinerte DocumentHandler.startElement () med strengen DIKT som argument. Du implementerer startElement () metode for å gjøre hva applikasjonen er ment å gjøre når en DIKT begynner. Strømmen av hendelser og resulterende samtaler for delen XML ovenfor vises i tabell 1 nedenfor.

Tabell 1. Sekvensen av tilbakeringinger som SAX produserer under analyse av liste 1
Gjenstand oppdagetParser tilbakeringing
{Begynnelsen på dokumentet}startDocument ()
startElement ("POEM", {AttributeList})
"\ n"tegn ("\ n ...", 6, 1)
startElement ("AUTHOR", {AttributeList})
"Ogden Nash"tegn ("\ n ...", 15, 10)
endElement ("FORfatter")
"\ n"tegn ("\ n ...", 34, 1)
startElement ("TITLE", {AttributeList})
"Lopper"tegn ("\ n ...", 42, 5)
endElement ("TITLE")
"\ n"tegn ("\ n ...", 55, 1)
startElement ("LINE", {AttributeList})
"Adam"tegn ("\ n ...", 62, 4)
endElement ("LINE")
startElement ("LINE", {AttributeList})
"Hadde dem."tegn ("\ n ...", 67, 8)
endElement ("LINE")
"\ n"tegn ("\ n ...", 82, 1)
endElement ("POEM")
{Slutten av dokumentet}endDocument ()

Du lager en klasse som implementeres DocumentHandler for å svare på hendelser som oppstår i SAX-parseren. Disse arrangementer er ikke Java-hendelser som du kanskje kjenner dem fra Abstract Windowing Toolkit (AWT). Dette er forhold som SAX-parseren oppdager når den analyseres, for eksempel starten på et dokument eller forekomsten av en lukkemerke i inngangsstrømmen. Når hver av disse forholdene (eller hendelsene) oppstår, kaller SAX metoden som tilsvarer tilstanden i sin DocumentHandler.

Så nøkkelen til å skrive programmer som behandler XML med SAX er å finne ut hva DocumentHandler bør gjøre som svar på en strøm av tilbakekallinger fra metoder fra SAX. SAX-parseren tar seg av all mekanikken til å identifisere koder, erstatte enhetsverdier og så videre, slik at du kan konsentrere deg om den applikasjonsspesifikke funksjonaliteten som bruker dataene som er kodet i XML.

Tabell 1 viser bare hendelser knyttet til elementer og tegn. SAX inkluderer også fasiliteter for håndtering av andre strukturelle funksjoner i XML-filer, for eksempel enheter og behandlingsinstruksjoner, men disse er utenfor omfanget av denne artikkelen.

Den kloke leseren vil legge merke til at et XML-dokument kan vises som et tre av typede objekter, og at rekkefølgen på strømmen av hendelser som presenteres for DocumentHandler tilsvarer en rekkefølge i dybden av dokumenttreet. (Det er ikke viktig å forstå dette punktet, men konseptet med et XML-dokument som en tredatastruktur er nyttig i mer sofistikerte typer dokumentbehandling, som vil bli dekket i senere artikler i denne serien.)

Nøkkelen til å forstå hvordan du bruker SAX er å forstå DocumentHandler grensesnitt, som jeg vil diskutere videre.

Tilpass parseren med org.xml.sax.DocumentHandler

Siden DocumentHandler grensesnittet er så sentralt i behandlingen av XML med SAX, det er verdt å forstå hva metodene i grensesnittet gjør. Jeg vil dekke de viktigste metodene i denne delen, og hoppe over de som omhandler mer avanserte emner. Huske, DocumentHandler er et grensesnitt, så metodene jeg beskriver er metoder som du vil implementere for å håndtere applikasjonsspesifikk funksjonalitet når den tilsvarende hendelsen inntreffer.

Dokument initialisering og opprydding

For hvert dokument som blir analysert, kaller SAX XML-analysatoren DocumentHandler grensesnittmetoder startDocument () (ringes før behandlingen begynner) og endDocument () (ringes etter at behandlingen er fullført). Du kan bruke disse metodene til å initialisere DocumentHandler for å forberede den for mottak av hendelser og for å rydde opp eller produsere resultater etter at analyseringen er fullført. endDocument () er spesielt interessant, siden det bare kalles hvis et inngangsdokument har blitt analysert. Hvis den Parser genererer en alvorlig feil, den avbryter ganske enkelt hendelsesstrømmen og slutter å analysere, og endDocument () blir aldri kalt.

Behandler koder

SAX-parseren ringer startElement () når den møter en åpen tag, og endElement () når den møter en nær tag. Disse metodene inneholder ofte koden som gjør det meste av arbeidet mens du analyserer en XML-fil. startElement ()Det første argumentet er en streng, som er kodenavnet til elementet du møter. Det andre argumentet er et objekt av typen Attributtliste, et grensesnitt definert i pakken org.xml.sax som gir sekvensiell eller tilfeldig tilgang til elementattributter etter navn. (Du har utvilsomt sett attributter før i HTML; i linjen

, GRENSE er et attributt hvis verdi er "1"). Siden Listing 1 ikke inneholder noen attributter, vises de ikke i tabell 1. Du vil se eksempler på attributter i eksempelapplikasjonen senere i denne artikkelen.

Siden SAX ikke gir noen informasjon om konteksten til elementene den møter (det vises inne i liste 1 ovenfor, for eksempel), er det opp til deg å oppgi den informasjonen. Applikasjonsprogrammerere bruker ofte stabler i startElement () og endElement (), skyver objekter på en bunke når et element starter, og skyver dem av bunken når elementet slutter.

Behandle tekstblokker

De tegn() metoden indikerer tegninnhold i XML-dokumentet - tegn som ikke vises i en XML-tag, med andre ord. Denne metodens signatur er litt rart. Det første argumentet er en rekke byte, den andre er en indeks i den matrisen som indikerer det første tegnet i området som skal behandles, og det tredje argumentet er lengden på tegnområdet.

Det kan se ut som om en enklere API rett og slett ville ha bestått en String objekt som inneholder dataene, men tegn() ble definert på denne måten av effektivitetshensyn. Parseren har ingen måte å vite om du skal bruke tegnene eller ikke, så når parseren analyserer inngangsbufferen, sender den en referanse til bufferen og indeksene til strengen den ser på, og stoler på at du vil konstruere din egen String hvis du vil ha en. Det er litt mer arbeid, men det lar deg bestemme om du vil pådra deg overhead String konstruksjon for innholdsstykker i en XML-fil.

De tegn() metoden håndterer både vanlig tekstinnhold og innhold i CDATA-seksjoner, som brukes til å forhindre at blokker av bokstavelig tekst blir analysert av en XML-parser.

Andre metoder

Det er tre andre metoder i DocumentHandler grensesnitt: ignorableWhitespace (), prosesseringsinstruksjon (), og setDocumentLocator (). ignorableWhitespace () rapporterer forekomster av hvite mellomrom, og er vanligvis ubrukt i ikke-validerende SAX-parsere (som den vi bruker for denne artikkelen); prosesseringsinstruksjon () håndterer det meste innen og ?> avgrensere; og setDocumentLocator () er valgfritt implementert av SAX-parsere for å gi deg tilgang til stedene for SAX-hendelser i den opprinnelige inngangsstrømmen. Du kan lese om disse metodene ved å følge koblingene på SAX-grensesnittene i Resources.

Å implementere alle metodene i et grensesnitt kan være kjedelig hvis du bare er interessert i oppførselen til en eller to av dem. SAX-pakken inkluderer en klasse som heter HandlerBase som i utgangspunktet ikke gjør noe, men kan hjelpe deg med å utnytte bare en eller to av disse metodene. La oss undersøke denne klassen mer detaljert.

HandlerBase: En gjør-ingenting-klasse

Ofte er du bare interessert i å implementere en eller to metoder i et grensesnitt, og vil at de andre metodene ganske enkelt ikke skal gjøre noe. Klassen org.xml.sax.HandlerBase forenkler implementeringen av DocumentHandler grensesnitt ved å implementere alle grensesnittets metoder med gjør-ingenting-organer. Så, i stedet for å implementere DocumentHandler, kan du underklasse HandlerBase, og bare overstyre metodene som interesserer deg.

Si for eksempel at du ønsket å skrive et program som nettopp skrev ut tittelen på et hvilket som helst XML-formatert dikt (som f.eks TitleFinder i oppføring 1). Du kan definere en ny DocumentHandler, som den i Listing 2 nedenfor, som underklasser HandlerBaseog overstyrer bare metodene du trenger. (Se Ressurser for en HTML-fil av TitleFinder.)

012 / ** 013 * SAX DocumentHandler-klasse som skriver ut innholdet i "TITLE" -element 014 * i et inngangsdokument. 015 * / 016 offentlig klasse TitleFinder utvider HandlerBase {017 boolean _isTitle = false; 018 offentlig TitleFinder () {019 super (); 020} 021 / ** 022 * Skriv ut tekst som er funnet i a  element. 023 * / 024 offentlige ugyldige tegn (char [] tegn, int iStart, int iLen) {025 hvis (_isTitle) {026 Streng sTitle = ny streng (tegn, iStart, iLen); 027 System.out.println ("Tittel:" + sTitle); 028} 029} 030 / ** 031 * Merk tittelelementets slutt. 032 * / 033 public void endElement (String element) {034 if (element.equals ("TITLE")) {035 _isTitle = false; 036} 037} 038 / ** 039 * Finn innholdet i titlene 040 * / 041 public static void main (String args []) {042 TitleFinder titleFinder = new TitleFinder (); 043 prøv {044 Parser parser = ParserFactory.makeParser ("com.ibm.xml.parsers.SAXParser"); 045 parser.setDocumentHandler (titleFinder); 046 parser.parse (ny InputSource (args [0])); 047} fangst (unntak eks) {048; // OK, så noen ganger er latskap * ikke * en dyd. 049} 050} 051 / ** 052 * Merk tittelelementets start 053 * / 054 public void startElement (String element, AttributeList attrlist) {055 if (element.equals ("TITLE")) {056 _isTitle = true; 057} 058} 

Oppføring 2. TitleFinder: En DocumentHandler hentet fra HandlerBase som skriver ut TITLER

Copyright no.verticalshadows.com 2024

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