Programmering

XML-dokumentbehandling i Java ved hjælp af XPath og XSLT

Extensible Markup Language (XML) er bestemt en af ​​de hotteste teknologier i øjeblikket. Mens begrebet markup-sprog ikke er nyt, synes XML særlig attraktivt for Java- og internetprogrammerere. Java API til XML-parsing (JAXP; se ressourcer), der for nylig er blevet defineret gennem Java Community-processen, lover at give en fælles grænseflade til at få adgang til XML-dokumenter. W3C har defineret den såkaldte Document Object Model (DOM), som giver en standardgrænseflade til at arbejde med et XML-dokument i et træhierarki, mens Simple API til XML (SAX) lader et program analysere et XML-dokument sekventielt, baseret på en begivenhedshåndteringsmodel. Begge disse standarder (SAX er en de facto-standard) supplerer JAXP. Tilsammen giver disse tre API'er tilstrækkelig support til at håndtere XML-dokumenter i Java, og adskillige bøger på markedet beskriver deres anvendelse.

Denne artikel introducerer en måde at håndtere XML-dokumenter, der går ud over standard Java API'erne til manipulation af XML. Vi ser, at XPath og XSLT i mange tilfælde giver enklere og mere elegante måder at løse applikationsproblemer på. I nogle enkle prøver sammenligner vi en ren Java / XML-løsning med en, der bruger XPath og / eller XSLT.

Både XSLT og XPath er en del af XSL-specifikationen (Extensible Stylesheet Language) (se Ressourcer). XSL består af tre dele: selve XSL-sprogspecifikationen, XSL Transformations (XSLT) og XML Path Language (XPath). XSL er et sprog til transformation af XML-dokumenter; den indeholder en definition - Formatering af objekter - af, hvordan XML-dokumenter kan formateres til præsentation. XSLT angiver et ordforråd til omdannelse af et XML-dokument til et andet. Du kan betragte XSLT som XSL minus formateringsobjekter. XPath-sproget adresserer specifikke dele af XML-dokumenter og er beregnet til at blive brugt inden for et XSLT-typografiark.

Med henblik på denne artikel antages det, at du er fortrolig med det grundlæggende i XML og XSLT samt DOM API'erne. (For information og vejledninger om disse emner, se Ressourcer.)

Bemærk: Denne artikels kodeeksempler blev kompileret og testet med Apache Xerces XML-parseren og Apache Xalan XSL-processoren (se Ressourcer).

Problemet

Mange artikler og papirer, der beskæftiger sig med XML, siger, at det er det perfekte middel til at udføre en god designpraksis inden for webprogrammering: Model-View-Controller-mønsteret (MVC) eller, i enklere termer, adskillelsen af ​​applikationsdata fra præsentationsdata . Hvis applikationsdataene er formateret i XML, kan de let bindes - typisk i en servlet eller Java ServerPage - til f.eks. HTML-skabeloner ved hjælp af et XSL-typografiark.

Men XML kan gøre meget mere end blot at hjælpe med modelvisningsadskillelse til en applikations frontend. Vi ser i øjeblikket mere og mere udbredt brug af komponenter (for eksempel komponenter udviklet ved hjælp af EJB-standarden), der kan bruges til at samle applikationer, hvilket øger udviklerens produktivitet. Komponentgenanvendelighed kan forbedres ved at formatere de data, som komponenter håndterer på en standard måde. Faktisk kan vi forvente at se flere og flere offentliggjorte komponenter, der bruger XML til at beskrive deres grænseflader.

Fordi XML-formaterede data er sprogneutrale, bliver de anvendelige i tilfælde, hvor klienten til en given applikationstjeneste ikke er kendt, eller når den ikke må have nogen afhængighed af serveren. For eksempel i B2B-miljøer er det muligvis ikke acceptabelt for to parter at have afhængigheder af konkrete Java-objektgrænseflader til deres dataudveksling. Nye teknologier som Simple Object Access Protocol (SOAP) (se ressourcer) imødekommer disse krav.

Alle disse sager har en ting til fælles: data gemmes i XML-dokumenter og skal manipuleres af en applikation. For eksempel vil en applikation, der bruger forskellige komponenter fra forskellige leverandører, højst sandsynligt nødt til at ændre strukturen på (XML) -dataene for at få dem til at passe til applikationens behov eller overholde en given standard.

Kode skrevet ved hjælp af Java API'erne nævnt ovenfor vil bestemt gøre dette. Der er desuden flere og flere værktøjer til rådighed, som du kan omdanne et XML-dokument til en JavaBean og omvendt, hvilket gør det lettere at håndtere dataene fra et Java-program. I mange tilfælde behandler applikationen eller i det mindste en del af det blot et eller flere XML-dokumenter som input og konverterer dem til et andet XML-format som output. Brug af stilark i disse tilfælde er et levedygtigt alternativ, som vi vil se senere i denne artikel.

Brug XPath til at finde noder i et XML-dokument

Som nævnt ovenfor bruges XPath-sproget til at lokalisere bestemte dele af et XML-dokument. Som sådan er det beregnet til at blive brugt af et XSLT-stilark, men intet forhindrer os i at bruge det i vores Java-program for at undgå langvarig iteration over et DOM-elementhierarki. Faktisk kan vi lade XSLT / XPath-processoren gøre arbejdet for os. Lad os se på, hvordan dette fungerer.

Lad os antage, at vi har et applikationsscenarie, hvor et XML-kildedokument præsenteres for brugeren (muligvis efter at være blevet behandlet af et typografiark). Brugeren foretager opdateringer til dataene og sender kun de opdaterede poster tilbage til applikationen for at gemme netværksbåndbredde. Applikationen ser efter XML-fragmentet i kildedokumentet, der skal opdateres, og erstatter det med de nye data.

Vi opretter en lille prøve, der hjælper dig med at forstå de forskellige muligheder. I dette eksempel antager vi, at applikationen behandler adresseposter i en adressebog. En prøve adressebog dokument ser sådan ud:

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

Applikationen (muligvis, men ikke nødvendigvis, en servlet) holder en forekomst af adressebog i hukommelsen som en DOM Dokument objekt. Når brugeren ændrer en adresse, sender applikationens frontend kun den opdaterede element.

Det element bruges til entydigt at identificere en adresse; det fungerer som den primære nøgle. Dette giver ikke meget mening for en reel applikation, men vi gør det her for at holde tingene enkle.

Vi er nu nødt til at skrive en Java-kode, der hjælper os med at identificere element i kildetræet, der skal erstattes med det opdaterede element. Det findAddress () nedenstående metode viser, hvordan det kan opnås. Bemærk, at for at holde prøven kort, har vi udeladt den rette fejlhåndtering.

public Node findAddress (String name, Document source) {Element root = source.getDocumentElement (); NodeList nl = root.getChildNodes (); // gentag over alle adresseknudepunkter og find den, der har den rigtige adressat til (int i = 0; i

Koden ovenfor kunne højst sandsynligt optimeres, men det er indlysende, at iterering over DOM-træet kan være kedeligt og fejlagtigt. Lad os nu se på, hvordan målnoden kan placeres ved hjælp af en simpel XPath-erklæring. Erklæringen kunne se sådan ud:

// adresse [barn :: adressat [tekst () = 'Jim Smith']] 

Vi kan nu omskrive vores tidligere metode. Denne gang bruger vi XPath-erklæringen til at finde den ønskede node:

offentlig Node findAddress (strengnavn, dokumentkilde) kaster Undtagelse {// behov for at genskabe et par hjælperobjekter XMLParserLiaison xpathSupport = ny XMLParserLiaisonDefault (); XPathProcessor xpathParser = ny XPathProcessorImpl (xpathSupport); PrefixResolver prefixResolver = nyt PrefixResolverDefault (source.getDocumentElement ()); // opret XPath og initialiser det XPath xp = new XPath (); String xpString = "// adresse [underordnet :: adressat [tekst () = '" + navn + "']]"; xpathParser.initXPath (xp, xpString, prefixResolver); // udfør nu XPath select-sætningen XObject-liste = xp.execute (xpathSupport, source.getDocumentElement (), prefixResolver); // returner den resulterende node-returliste. nodeset (). item (0); } 

Ovenstående kode ser muligvis ikke meget bedre ud end det forrige forsøg, men det meste af denne metodes indhold kan være indkapslet i en hjælperklasse. Den eneste del, der ændres igen og igen, er det faktiske XPath-udtryk og målnoden.

Dette giver os mulighed for at oprette en XPathHelper klasse, der ser sådan ud:

import org.w3c.dom. *; import org.xml.sax. *; import org.apache.xalan.xpath. *; importer org.apache.xalan.xpath.xml. *; offentlig klasse XPathHelper {XMLParserLiaison xpathSupport = null; XPathProcessor xpathParser = null; PrefixResolver prefixResolver = null; XPathHelper () {xpathSupport = ny XMLParserLiaisonDefault (); xpathParser = ny XPathProcessorImpl (xpathSupport); } offentlig NodeList procesXPath (String xpath, Node mål) thrws SAXException {prefixResolver = new PrefixResolverDefault (target); // Opret XPath og initialiser den XPath xp = ny XPath (); xpathParser.initXPath (xp, xpath, prefixResolver); // udfør nu XPath select-sætningen XObject-liste = xp.execute (xpathSupport, target, prefixResolver); // returner den resulterende node-returliste. nodeset (); }} 

Efter at have oprettet hjælperklassen kan vi omskrive vores findermetode igen, som nu er meget kort:

offentlig node findAddress (strengnavn, dokumentkilde) kaster undtagelse {XPathHelper xpathHelper = ny XPathHelper (); NodeList nl = xpathHelper.processXPath ("// address [child :: addressee [text () = '" + name + "']]", source.getDocumentElement ()); return nl.item (0); } 

Hjælperklassen kan nu bruges, når en node eller et sæt noder skal placeres i et givet XML-dokument. Den egentlige XPath-erklæring kunne endda indlæses fra en ekstern kilde, så ændringer kunne foretages i farten, hvis kildedokumentstrukturen ændres. I dette tilfælde er ingen rekompilering nødvendig.

Behandl XML-dokumenter med XSL-stilark

I nogle tilfælde er det fornuftigt at outsource hele håndteringen af ​​et XML-dokument til et eksternt XSL-stilark, en proces i nogle henseender svarende til brugen af ​​XPath som beskrevet i det foregående afsnit. Med XSL-typografiark kan du oprette et outputdokument ved at vælge noder fra inputdokumentet og flette deres indhold med stilarkindhold baseret på mønsterregler.

Hvis et program ændrer strukturen og indholdet af et XML-dokument og producerer et nyt dokument, kan det være bedre og lettere at bruge et typografiark til at håndtere arbejdet i stedet for at skrive et Java-program, der udfører det samme job. Stylearket gemmes sandsynligvis i en ekstern fil, så du kan ændre det i farten uden behov for at kompilere igen.

For eksempel kunne vi udføre behandlingen til adressebog prøve ved at oprette et typografiark, der fletter den cachelagrede version af adressebog med den opdaterede, hvorved der oprettes et nyt dokument med opdateringerne i det.

Her er et eksempel på et sådant stilark:

   //mymachine.com/changed.xml