Ohjelmointi

XML: n yhdistäminen Java-ohjelmaan, osa 1

XML on kuuma. Koska XML on itsekuvaavan datan muoto, sitä voidaan käyttää koodaamaan rikastietomalleja. XML: n hyödyllisyys on helppo nähdä tiedonvaihtovälineenä hyvin erilaisten järjestelmien välillä. Tiedot voidaan helposti paljastaa tai julkaista XML-muodossa kaikenlaisista järjestelmistä: vanhat COBOL-ohjelmat, tietokannat, C ++ -ohjelmat ja niin edelleen.

TEKSTILAATIKKO:

TEXTBOX_HEAD: XML: n yhdistäminen Java: han: Lue koko sarja!

  • Osa 1 - Käytä SAX-sovellusliittymää kartoittamaan XML-asiakirjat Java-objekteihin
  • Osa 2 - Luo luokkakirjasto, joka käyttää SAX-sovellusliittymää XML-dokumenttien kartoittamiseen Java-objekteihin

: END_TEXTBOX

XML: n käyttö järjestelmien rakentamiseen asettaa kuitenkin kaksi haastetta. Ensinnäkin, vaikka XML: n luominen on yksinkertainen menettely, käänteisoperaatio, joka käyttää XML-tietoja ohjelman sisällä, ei ole. Toiseksi nykyisiä XML-tekniikoita on helppo käyttää väärin, mikä voi jättää ohjelmoijalle hitaan, muistin nälkäisen järjestelmän. Raskaat muistivaatimukset ja hitaat nopeudet voivat todellakin olla ongelmallisia järjestelmille, jotka käyttävät XML: ää ensisijaisena tiedonsiirtomuotona.

Jotkut tällä hetkellä XML: n kanssa työskentelemiseen käytettävissä olevat vakiotyökalut ovat parempia kuin toiset. Varsinkin SAX-sovellusliittymässä on joitain tärkeitä ajonaikaisia ​​ominaisuuksia suorituskykyherkälle koodille. Tässä artikkelissa kehitämme joitain malleja SAX-sovellusliittymän käyttämiseen. Pystyt luomaan nopean XML-Java-kartoituskoodin, jolla on mahdollisimman vähän muistia, jopa melko monimutkaisille XML-rakenteille (rekursiivisia rakenteita lukuun ottamatta).

Tämän sarjan osassa 2 käsitellään SAX-sovellusliittymän soveltamista rekursiivisiin XML-rakenteisiin, joissa jotkut XML-elementit edustavat luetteloluetteloita. Kehitämme myös luokkakirjaston, joka hallinnoi SAX-sovellusliittymän navigointiin liittyviä näkökohtia. Tämä kirjasto yksinkertaistaa XML-kartoituskoodin kirjoittamista SAX: n perusteella.

Kartoituskoodi on samanlainen kuin koodin kääntäminen

XML-tietoja käyttävien ohjelmien kirjoittaminen on kuin kääntäjän kirjoittaminen. Eli suurin osa kääntäjistä muuntaa lähdekoodin suoritettavaksi ohjelmaksi kolmessa vaiheessa. Ensinnäkin a lexer moduuli ryhmittelee merkit sanoiksi tai tunnuksiksi, jotka kääntäjä tunnistaa - prosessi, joka tunnetaan merkinnöinä. Toinen moduuli, jota kutsutaan jäsennin, analysoi rahakkeiden ryhmiä laillisten kielirakenteiden tunnistamiseksi. Viimeinen, kolmas moduuli, koodigeneraattori, ottaa joukon laillista kieltä ja rakentaa suoritettavan koodin. Joskus jäsentäminen ja koodin luonti sekoitetaan keskenään.

Jotta voimme käyttää XML-tietoja Java-ohjelmassa, meidän on suoritettava samanlainen prosessi. Ensinnäkin analysoimme jokaisen merkin XML-tekstissä, jotta voimme tunnistaa lailliset XML-tunnukset, kuten aloitustunnisteet, määritteet, lopputunnisteet ja CDATA-osiot.

Toiseksi tarkistamme, että tunnukset muodostavat lailliset XML-rakenteet. Jos XML-asiakirja koostuu kokonaan XML 1.0 -määrityksen mukaisista juridisista rakenteista, niin se onkin hyvin muodostunut. Alkeellisimmalla tasolla meidän on varmistettava, että esimerkiksi kaikilla tunnisteilla on yhteensopivat aloitus- ja sulkutunnisteet ja että attribuutit on rakennettu oikein avaavassa tagissa.

Lisäksi, jos DTD on käytettävissä, meillä on mahdollisuus varmistaa, että jäsentämisen aikana löydetyt XML-rakenteet ovat laillisia DTD: n kannalta ja että ne ovat hyvin muotoiltuja XML-muotoja.

Lopuksi käytämme XML-asiakirjan sisältämiä tietoja saadaksemme aikaan jotain hyödyllistä - kutsun tätä XML-kartoitusta Javaiksi.

XML-jäsentimet

Onneksi on olemassa valmiita komponentteja - XML-jäsentimiä - jotka suorittavat joitain näistä kääntäjiin liittyvistä tehtävistä meille. XML-jäsentimet hoitavat kaikki leksikaaliset analyysi- ja jäsentämistehtävät meille. Monet tällä hetkellä saatavilla olevat Java-pohjaiset XML-jäsentimet tukevat kahta suosittua jäsentämisstandardia: SAX- ja DOM-sovellusliittymiä.

XML-jäsentimen saatavuus voi näyttää siltä, ​​että XML: n Java-käyttö on vaikea tehtävä sinulle. Todellisuudessa valmiiden XML-jäsentimien käyttö on mukana tehtävä.

SAX- ja DOM-sovellusliittymät

SAX-sovellusliittymä on tapahtumapohjainen. XML-jäsentimet, jotka toteuttavat SAX-sovellusliittymän, luovat tapahtumia, jotka vastaavat jäsennetyn XML-asiakirjan eri ominaisuuksia. Vastaamalla tähän SAX-tapahtumavirtaan Java-koodilla voit kirjoittaa XML-pohjaisen datan ohjaamia ohjelmia.

DOM-sovellusliittymä on objektimallipohjainen sovellusliittymä. DOM: n käyttöön ottavat XML-jäsentimet luovat muistiin yleisen objektimallin, joka edustaa XML-asiakirjan sisältöä. Kun XML-jäsennin on valmis jäsentämiseen, muisti sisältää DOM-objektien puun, joka tarjoaa tietoja sekä XML-asiakirjan rakenteesta että sisällöstä.

DOM-käsite kasvoi HTML-selainmaailmasta, jossa yhteinen asiakirjaobjektimalli edustaa selaimeen ladattua HTML-asiakirjaa. Tämä HTML DOM tulee sitten käytettäväksi komentosarjakielille, kuten JavaScript. HTML DOM on ollut erittäin onnistunut tässä sovelluksessa.

DOM: n vaarat

Ensi silmäyksellä DOM-sovellusliittymä näyttää olevan monipuolisempi ja siten parempi kuin SAX-sovellusliittymä. DOM: lla on kuitenkin vakavia tehokkuusongelmia, jotka voivat vahingoittaa suorituskykyherkkiä sovelluksia.

Nykyinen DOMia tukevien XML-jäsentäjien ryhmä toteuttaa muistissa olevan objektimallin luomalla monia pieniä objekteja, jotka edustavat DOM-solmuja, jotka sisältävät joko tekstiä tai muita DOM-solmuja. Tämä kuulostaa tarpeeksi luonnolliselta, mutta sillä on negatiivisia vaikutuksia suorituskykyyn. Yksi Java: n kalleimmista toiminnoista on Uusi operaattori. Vastaavasti jokaiselle Uusi JVM-roskakorin on lopulta poistettava objekti muistista, kun viitteitä esineeseen ei ole jäljellä. DOM-sovellusliittymä pyrkii todella tuhoamaan JVM-muistijärjestelmän monilla pienillä esineillä, jotka yleensä heitetään sivuun pian jäsentämisen jälkeen.

Toinen DOM-ongelma on se, että se lataa koko XML-asiakirjan muistiin. Suurten asiakirjojen kohdalla siitä tulee ongelma. Jälleen kerran, koska DOM on toteutettu niin monena pienenä objektina, muistin jalanjälki on jopa suurempi kuin itse XML-asiakirja, koska JVM tallentaa muutaman ylimääräisen tavun tietoja kaikista näistä objekteista sekä XML-asiakirjan sisällöstä.

On myös huolestuttavaa, että monet Java-ohjelmat eivät todellakaan käytä DOM: n yleistä objektirakennetta. Sen sijaan heti, kun DOM-rakenne latautuu muistiin, ne kopioivat tiedot tietylle ongelma-alueelle ominaiseen objektimalliin - hienovaraiseen mutta tuhlaavaan prosessiin.

Toinen hienovarainen ongelma DOM-sovellusliittymälle on, että sille kirjoitetun koodin on skannattava XML-asiakirja kahdesti. Ensimmäinen syöttö luo DOM-rakenteen muistiin, toinen etsii kaikki ohjelmasta kiinnostuneet XML-tiedot. Tietyt koodaustyylit saattavat kulkea DOM-rakenteen useita kertoja samalla, kun ne etsivät erilaisia ​​XML-tietoja. Sitä vastoin SAX: n koodityyli kannustaa XML-tietojen paikantamiseen ja keräämiseen yhdellä kertaa.

Joitakin näistä ongelmista voitaisiin ratkaista paremmalla taustalla olevalla tietorakenteella, joka edustaa DOM-objektimallia sisäisesti. XML-jäsentimissä ei voida käsitellä esimerkiksi useita prosessointilupien kannustamista ja kääntämistä yleisten ja tiettyjen objektimallien välillä.

SAX selviytymiseen

DOM-sovellusliittymään verrattuna SAX-sovellusliittymä on houkutteleva lähestymistapa. SAX: lla ei ole yleistä objektimallia, joten sillä ei ole muistiin tai suorituskykyyn liittyviä ongelmia Uusi operaattori. Ja SAX: n kanssa ei ole mitään yleistä objektimallia, jota ei voida sivuuttaa, jos aiot käyttää sen sijaan tiettyä ongelma-toimialue-objektimallia. Lisäksi, koska SAX käsittelee XML-asiakirjan yhdellä kertaa, se vaatii paljon vähemmän käsittelyaikaa.

SAX: lla on muutamia haittoja, mutta ne liittyvät enimmäkseen ohjelmoijaan, eivät API: n ajonaikaisiin suorituksiin. Katsotaanpa muutama.

Ensimmäinen haitta on käsitteellinen. Ohjelmoijat ovat tottuneet navigoimaan tietojen saamiseksi; löytää tiedosto tiedostopalvelimelta siirtymällä muuttamalla hakemistoja. Vastaavasti, saadaksesi tietoja tietokannasta, kirjoitat tarvitsemillesi tiedoille SQL-kyselyn. SAX: n kanssa tämä malli on käänteinen. Eli määrität koodin, joka kuuntelee luetteloa kaikista käytettävissä olevista XML-tiedoista. Koodi aktivoituu vain, kun mielenkiintoisia XML-tietoja luetellaan. Aluksi SAX-sovellusliittymä näyttää oudolta, mutta jonkin ajan kuluttua ajattelusta tällä käänteisellä tavalla tulee toinen luonne.

Toinen haitta on vaarallisempi. SAX-koodilla naiivi "otamme hakkaan siihen" -lähestymistapa palaa melko nopeasti, koska SAX-jäsennin navigoi tyhjentävästi XML-rakennetta ja toimittaa samanaikaisesti XML-asiakirjaan tallennettuja tietoja. Suurin osa ihmisistä keskittyy tietojen kartoittamiseen ja laiminlyö navigointinäkökulman. Jos et käsittele suoraan SAX-jäsentämisen navigointinäkökohtaa, koodi, joka seuraa sijaintia XML-rakenteessa SAX-jäsentämisen aikana, leviää ja sillä on monia hienovaraisia ​​vuorovaikutuksia. Tämä ongelma on samanlainen kuin liiallisesta riippuvuudesta globaaleista muuttujista. Mutta jos opit rakentamaan SAX-koodin oikein pitämään se hankalana, se on suoraviivaisempaa kuin DOM-sovellusliittymän käyttö.

Perus SAX

Tällä hetkellä SAX-sovellusliittymästä on julkaistu kaksi versiota. Käytämme esimerkissä versiota 2 (katso Resurssit). Versio 2 käyttää eri luokkien ja menetelmien nimiä kuin versio 1, mutta koodin rakenne on sama.

SAX on API, ei jäsennin, joten tämä koodi on yleinen XML-jäsentimissä. Saadaksesi esimerkit suoritettavaksi, sinun on käytettävä XML-jäsennintä, joka tukee SAX v2: ta. Käytän Apachen Xerces-jäsennintä. (Katso Resurssit.) Tarkista jäsentäjän aloitusoppaasta SAX-jäsentimen kutsumisen yksityiskohdat.

SAX API -määrittely on melko yksinkertainen. Sisältää monia yksityiskohtia, mutta sen ensisijainen tehtävä on luoda luokka, joka toteuttaa ContentHandler käyttöliittymä, XML-jäsentäjien käyttämä takaisinkäyttöliittymä, joka ilmoittaa ohjelmalle SAX-tapahtumista, kuten ne löytyvät XML-asiakirjasta.

SAX API tarjoaa myös kätevästi a Oletuskäsittelijä toteutuksen luokka ContentHandler käyttöliittymä.

Kun olet ottanut käyttöön ContentHandler tai laajennettu Oletuskäsittelijä, sinun tarvitsee vain ohjata XML-jäsennin jäsentämään tietty asiakirja.

Ensimmäinen esimerkkimme laajentaa Oletuskäsittelijä tulostaa kukin SAX-tapahtuma konsolille. Tämä antaa sinulle tuntuman siitä, mitä SAX-tapahtumia luodaan ja missä järjestyksessä.

Aloittamiseksi tässä on esimerkki XML-dokumentista, jota käytämme ensimmäisessä esimerkissämme:

   Bob New York 

Seuraavaksi näemme ensimmäisen esimerkin XML-kartoituskoodin lähdekoodin:

tuo org.xml.sax. *; tuo org.xml.sax.helpers. *; tuo java.io. *; public class Esimerkki1 laajentaa DefaultHandler {// DefaultHandler-luokan // menetelmien ohittamista saadakseen ilmoituksen SAX-tapahtumista. // // Katso kaikki saatavilla olevat tapahtumat kohdasta org.xml.sax.ContentHandler. // public void startDocument () heittää SAXException {System.out.println ("SAX-tapahtuma: ALOITA DOKUMENTTI"); } public void endDocument () heittää SAXException {System.out.println ("SAX-tapahtuma: LOPETA DOKUMENTTI"); } public void startElement (Merkkijonon nimitila SPURI, String paikallinenNimi, String qName, Attribuutit attr) heittää SAXException {System.out.println ("SAX-tapahtuma: START ELEMENT [" + paikallinenNimi + "]"); // Tulostetaan myös määritteet, jos // niitä on ... kohteelle (int i = 0; i <attr.getLength (); i ++) {System.out.println ("ATTRIBUTE:" + attr.getLocalName ( i) + "ARVO:" + attr.getValue (i)); }} public void endElement (String namespaceURI, String localName, String qName) heittää SAXException {System.out.println ("SAX-tapahtuma: END ELEMENT [" + paikallinenNimi + "]"); } julkiset tyhjät merkit (char [] ch, int start, int length) heittää SAXException {System.out.print ("SAX-tapahtuma: MERKIT ["); kokeile {OutputStreamWriter outw = uusi OutputStreamWriter (System.out); outw.write (ch, alku, pituus); outw.flush (); } catch (Poikkeus e) {e.printStackTrace (); } System.out.println ("]"); } public static void main (String [] argv) {System.out.println ("Esimerkki 1 SAX-tapahtumat:"); kokeile {// Luo SAX 2-jäsennin ... XMLReader xr = XMLReaderFactory.createXMLReader (); // Aseta ContentHandler ... xr.setContentHandler (uusi esimerkki1 ()); // jäsennä tiedosto ... xr.parse (new InputSource (new FileReader ("Example1.xml"))); } catch (Poikkeus e) {e.printStackTrace (); }}} 

Lopuksi tässä on tuotos, joka syntyy suorittamalla ensimmäinen esimerkki XML-esimerkkidokumenttimme kanssa:

Esimerkki 1 SAX-tapahtumat: SAX-tapahtuma: START DOCUMENT SAX-tapahtuma: START ELEMENT [yksinkertainen] ATTRIBUTE: päivämäärä ARVO: 7/7/2000 SAX-tapahtuma: CHARACTERS [] SAX-tapahtuma: START ELEMENT [nimi] SAX-tapahtuma: CHARACTERS [Bob] SAX-tapahtuma : END ELEMENT [nimi] SAX-tapahtuma: CHARACTERS [] SAX-tapahtuma: START ELEMENT [sijainti] SAX-tapahtuma: CHARACTERS [New York] SAX-tapahtuma: END ELEMENT [sijainti] SAX-tapahtuma: CHARACTERS [] SAX-tapahtuma: END ELEMENT [yksinkertainen] SAX-tapahtuma: LOPETA DOKUMENTTI 

Kuten näette, SAX-jäsennin kutsuu sopivan ContentHandler menetelmä jokaiselle SAX-tapahtumalle, jonka se löytää XML-dokumentista.

Hei maailma

Nyt kun olemme ymmärtäneet SAX: n perusmallin, voimme alkaa tehdä jotain hieman hyödyllistä: poimia arvot yksinkertaisesta XML-dokumentistamme ja esitellä klassinen hello world -ohjelma.

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