Obrada XML dokumenata u Javi pomoću XPath i XSLT

Proširivi označni jezik (XML) zasigurno je jedna od najtraženijih tehnologija u ovom trenutku. Iako koncept označnih jezika nije nov, XML se čini posebno privlačnim za programere Java i Internet. Java API za XML raščlanjivanje (JAXP; vidi Resursi), koji je nedavno definiran kroz Java Community Process, obećava pružiti zajedničko sučelje za pristup XML dokumentima. W3C je definirao takozvani Model objekta dokumenta (DOM), koji pruža standardno sučelje za rad s XML dokumentom u hijerarhiji stabla, dok Jednostavni API za XML (SAX) omogućuje programu sekvencijalno raščlanjivanje XML dokumenta na temelju na modelu upravljanja događajima. Oba ova standarda (SAX je de facto standard) nadopunjuju JAXP. Ova tri API-ja zajedno pružaju dovoljnu podršku za rješavanje XML dokumenata u Javi,a brojne knjige na tržištu opisuju njihovu upotrebu.

Ovaj članak predstavlja način za rukovanje XML dokumentima koji nadilazi standardne Java API-je za manipulaciju XML-om. Vidjet ćemo da u mnogim slučajevima XPath i XSLT pružaju jednostavnije, elegantnije načine rješavanja aplikacijskih problema. U nekim jednostavnim uzorcima usporedit ćemo čisto Java / XML rješenje s onim koje koristi XPath i / ili XSLT.

I XSLT i XPath dio su specifikacije proširivog jezika stilskog lista (XSL) (vidi Resursi). XSL se sastoji od tri dijela: sama specifikacija jezika XSL, XSL transformacije (XSLT) i XML jezik puta (XPath). XSL je jezik za pretvaranje XML dokumenata; uključuje definiciju - Oblikovanje objekata - načina na koji se XML dokumenti mogu oblikovati za prezentaciju. XSLT određuje rječnik za pretvaranje jednog XML dokumenta u drugi. XSLT možete smatrati XSL-om minus formatiranje objekata. Jezik XPath obraća se određenim dijelovima XML dokumenata i namijenjen je korištenju u XSLT tablici stilova.

Za potrebe ovog članka pretpostavlja se da ste upoznati s osnovama XML-a i XSLT-a, kao i s DOM API-ima. (Za informacije i upute o tim temama pogledajte Resursi.)

Napomena: Uzorci koda ovog članka sastavljeni su i testirani s analizatorom Apache Xerces XML i procesorom Apache Xalan XSL (vidi Resursi).

Problem

Mnogi članci i radovi koji se bave XML-om tvrde da je savršeno sredstvo za postizanje dobre prakse dizajna u web programiranju: obrazac Model-View-Controller (MVC) ili, jednostavnije rečeno, odvajanje podataka aplikacije od podataka prezentacije . Ako su podaci aplikacije formatirani u XML-u, mogu se lako vezati - obično u servlet ili Java ServerPage - na, recimo, HTML predloške pomoću XSL tablice stilova.

Ali XML može učiniti mnogo više od pukog pomaganja u razdvajanju pogleda modela za sučelje aplikacije. Trenutno promatramo sve rašireniju upotrebu komponenata (na primjer, komponenata razvijenih pomoću EJB standarda) koje se mogu koristiti za sastavljanje aplikacija, čime se povećava produktivnost programera. Ponovna upotrebljivost komponenata može se poboljšati formatiranjem podataka s kojima komponente rade na standardni način. Zaista, možemo očekivati ​​da ćemo vidjeti sve više objavljenih komponenata koje koriste XML za opisivanje svojih sučelja.

Budući da su podaci oblikovani u XML jezično neutralni, oni postaju upotrebljivi u slučajevima kada klijent dane aplikacijske usluge nije poznat ili kada ne smije imati ovisnosti o poslužitelju. Na primjer, u B2B okruženjima možda nije prihvatljivo da dvije strane imaju ovisnosti o konkretnim Java objektnim sučeljima za razmjenu podataka. Nove se tehnologije poput Jednostavnog protokola za pristup objektima (SOAP) (vidi Resursi) bave tim zahtjevima.

Svi ovi slučajevi imaju jedno zajedničko: podaci se pohranjuju u XML dokumente i njima treba upravljati aplikacija. Na primjer, aplikacija koja koristi različite komponente različitih dobavljača najvjerojatnije će morati promijeniti strukturu (XML) podataka kako bi odgovarala potrebama aplikacije ili se pridržavala određenog standarda.

Kod napisan pomoću gore spomenutih Java API-ja sigurno bi to učinio. Štoviše, dostupno je sve više alata pomoću kojih možete pretvoriti XML dokument u JavaBean i obrnuto, što olakšava rukovanje podacima iz Java programa. Međutim, u mnogim slučajevima aplikacija ili barem njezin dio samo obrađuje jedan ili više XML dokumenata kao ulaz i pretvara ih u drugi XML format kao izlaz. Korištenje tablica stilova u tim je slučajevima održiva alternativa, kao što ćemo vidjeti kasnije u ovom članku.

Upotrijebite XPath za pronalaženje čvorova u XML dokumentu

Kao što je gore rečeno, jezik XPath koristi se za pronalaženje određenih dijelova XML dokumenta. Kao takav, zamišljen je za upotrebu u XSLT tablici stilova, ali ništa nas ne sprečava da ga koristimo u našem Java programu kako bismo izbjegli dugotrajno ponavljanje hijerarhije DOM elemenata. Doista, možemo pustiti da XSLT / XPath procesor obavi posao umjesto nas. Pogledajmo kako to funkcionira.

Pretpostavimo da imamo scenarij aplikacije u kojem se korisniku predstavlja izvorni XML dokument (moguće nakon obrade u stilskoj tablici). Korisnik ažurira podatke i, radi uštede propusnosti mreže, aplikaciji šalje samo ažurirane zapise. Aplikacija traži XML fragment u izvornom dokumentu koji treba ažurirati i zamjenjuje ga novim podacima.

Napravit ćemo mali uzorak koji će vam pomoći da razumijete razne mogućnosti. Za ovaj primjer pretpostavljamo da se aplikacija bavi zapisima adresa u addressbook. Uzorak addressbookdokumenta izgleda ovako:

  John Smith 250 18th Ave SE Rochester MN 55902 Bill Morris 1234 Center Lane NW St. Paul MN 55123   

Aplikacija (moguće, iako ne nužno, servlet) čuva primjerak datoteke addressbooku memoriji kao DOM Documentobjekt. Kada korisnik promijeni adresu, sučelje aplikacije šalje joj samo ažurirani element.

Element koristi za jedinstvenu identifikaciju adrese; služi kao primarni ključ. To ne bi imalo puno smisla za stvarnu aplikaciju, ali to radimo ovdje kako bismo pojednostavili stvari.

Sada moramo napisati neki Java kôd koji će nam pomoći identificirati element u izvornom stablu koji treba zamijeniti ažuriranim elementom. findAddress()Metoda u nastavku pokazuje kako se to može postići. Imajte na umu da smo, kako bi uzorak bio kratak, izostavili odgovarajuće postupanje s pogreškama.

javni čvor findAddress (naziv niza, izvor dokumenta) {Element root = source.getDocumentElement (); Popis čvorova nl = root.getChildNodes (); // prelistavanje svih adresnih čvorova i pronalazak onog za kojeg je točan adresat (int i = 0; i
   
    

Gornji kod najvjerojatnije bi mogao biti optimiziran, ali očito je da ponavljanje DOM stabla može biti zamorno i podložno pogreškama. Sada pogledajmo kako se ciljni čvor može pronaći pomoću jednostavne XPath izjave. Izjava bi mogla izgledati ovako:

// adresa [dijete :: adresat [tekst () = 'Jim Smith']] 

Sada možemo prepisati našu prethodnu metodu. Ovaj put koristimo naredbu XPath za pronalaženje željenog čvora:

javni čvor findAddress (naziv niza, izvor dokumenta) baca izuzetak {// treba stvoriti nekoliko pomoćnih objekata XMLParserLiaison xpathSupport = novi XMLParserLiaisonDefault (); XPathProcessor xpathParser = novi XPathProcessorImpl (xpathSupport); PrefixResolver prefixResolver = novi PrefixResolverDefault (source.getDocumentElement ()); // stvorimo XPath i inicijaliziramo ga XPath xp = new XPath (); Niz xpString = "// adresa [dijete :: adresac [tekst () = '" + ime + "']]"; xpathParser.initXPath (xp, xpString, prefixResolver); // sada izvršimo naredbu XPath select XObject list = xp.execute (xpathSupport, source.getDocumentElement (), prefixResolver); // vratimo rezultirajući popis za povratak čvora.nodeset (). item (0); }

Gornji kôd možda neće izgledati puno bolje od prethodnog pokušaja, ali većina sadržaja ove metode može se uvrstiti u pomoćnu klasu. Jedini dio koji se uvijek iznova mijenja je stvarni XPath izraz i ciljni čvor.

To nam omogućuje stvaranje XPathHelperklase koja izgleda ovako:

import org.w3c.dom.*; import org.xml.sax.*; import org.apache.xalan.xpath.*; import org.apache.xalan.xpath.xml.*; public class XPathHelper { XMLParserLiaison xpathSupport = null; XPathProcessor xpathParser = null; PrefixResolver prefixResolver = null; XPathHelper() { xpathSupport = new XMLParserLiaisonDefault(); xpathParser = new XPathProcessorImpl(xpathSupport); } public NodeList processXPath(String xpath, Node target) thrws SAXException { prefixResolver = new PrefixResolverDefault(target); // create the XPath and initialize it XPath xp = new XPath(); xpathParser.initXPath(xp, xpath, prefixResolver); // now execute the XPath select statement XObject list = xp.execute(xpathSupport, target, prefixResolver); // return the resulting node return list.nodeset(); } } 

After creating the helper class, we can rewrite our finder method again, which is now very short:

public Node findAddress(String name, Document source) throws Exception { XPathHelper xpathHelper = new XPathHelper(); NodeList nl = xpathHelper.processXPath( "//address[child::addressee[text() = '"+name+"']]", source.getDocumentElement()); return nl.item(0); } 

The helper class can now be used whenever a node or a set of nodes needs to be located in a given XML document. The actual XPath statement could even be loaded from an external source, so that changes could be made on the fly if the source document structure changes. In this case, no recompile is necessary.

Process XML documents with XSL stylesheets

In some cases, it makes sense to outsource the entire handling of an XML document to an external XSL stylesheet, a process in some respects similar to the use of XPath as described in the previous section. With XSL stylesheets, you can create an output document by selecting nodes from the input document and merging their content with stylesheet content, based on pattern rules.

If an application changes the structure and content of an XML document and producing a new document, it may be better and easier to use a stylesheet to handle the work rather than writing a Java program that does the same job. The stylesheet is most likely stored in an external file, allowing you to change it on the fly, without the need to recompile.

Na primjer, mogli bismo izvršiti obradu addressbookuzorka stvaranjem stilskog lista koji spaja predmemoriranu verziju addressbooks ažuriranom, stvarajući tako novi dokument s ažuriranjima u njemu.

Evo primjera takvog lista stilova:

   //mymachine.com/changed.xml