XSLT cvjeta s Javom

Je li vas ikad spotaknuo težak problem transformacije XML-a koji niste mogli riješiti samo pomoću XSLT (Proširiva transformacija jezika stilskog lista)? Uzmimo za primjer jednostavnu tablicu stilova filtra koja odabire samo one čvorove starije od prije pet dana. Čuli ste da XSLT može filtrirati XML dokumente, pa pretpostavljate da ćete taj problem riješiti u kratkom vremenu. Prvi je zadatak dobivanje današnjeg datuma iz tablice stilova, pod uvjetom da podaci nisu uključeni u izvorni XML dokument. Nažalost, ovaj zadatak ne možete izvršiti samo s XSLT-om. U situaciji kao što je ova, možete pojednostaviti svoj XSLT kôd i brže riješiti problem pomoću Java nastavka.

Mnogi XSLT procesori omogućuju neke vrste produžnih mehanizama; specifikacija to zahtijeva. U svijetu Jave i XML-a, najrasprostranjeniji XSLT procesor je procesor Apache Xalan otvorenog koda. Napisan na Javi, Xalan omogućuje proširenja na Javi. Mnogi programeri smatraju da je Xalanova proširivost moćna jer im omogućuje da koriste svoje Java sposobnosti iz konteksta tablice stilova. Razmotrite način na koji JSP-ovi (JavaServer stranice), skripte i prilagođene oznake dodaju snagu HTML-u. Proširenja Xalan na sličan način dodaju snagu stilskim tablicama: dopuštajući programerima Java pristup njihovom omiljenom alatu Java.

U ovom ću članku pokazati kako možete koristiti Javu iz XSLT tablice stilova. Prvo ćemo upotrijebiti Xalanovu proširivost za instanciranje i korištenje postojećih klasa unutar JDK. Kasnije ću vam pokazati kako napisati funkciju proširenja XSLT koja uzima Stringargument i vraća fragment DOM (objektni model dokumenta) u procesor tabele stilova.

XSLT je važan za programere J2EE (Java 2 Platform, Enterprise Edition) jer je oblikovanje XML dokumenata postalo operacija na strani poslužitelja. Također, JAXP (Java API za XML obradu), koji uključuje podršku za XSLT motore, postao je dio J2EE specifikacije (J2EE 2.6.11). U povojima je XSLT trebao oblikovati XML na klijentu; međutim, većina aplikacija oblikuje XML prije nego što ga pošalje klijentu. Za programere J2EE to znači da će se XSLT procesor najvjerojatnije izvoditi unutar poslužitelja aplikacija.

Prije nego što nastavite s ovim člankom, upozorite da će korištenje Java proširenja u vašim XSLT tablicama stilova smanjiti njihovu prenosivost. Iako su proširenja dio XSLT specifikacije, način na koji su implementirani nije. Ako će se vaše tablice stilova izvoditi na procesorima koji nisu Xalan, poput mehanizma za izradu tablica stilova Internet Explorera, trebali biste izbjegavati upotrebu proširenja pod svaku cijenu.

XSLT slabosti

Budući da XSLT ima nekoliko slabih mjesta, XSLT proširenja pokazuju se vrlo korisnima. Ne kažem da je XSLT loš; međutim, jednostavno ne nudi najbolji alat za obradu svega u XML dokumentu. Razmotrite ovaj odjeljak XML-a:

 XSLT nije tako jednostavan za upotrebu kao što bi neki htjeli vas ...   

Pretpostavimo da vas šef traži da izmijenite tablicu stilova tako da pretvara sve primjerke "nije" u "nije" i lokalizira uobičajene oznake. Svakako XSLT pruža mehanizam za poduzimanje nečega u tom smislu, zar ne? Pogrešno. XSLT ne pruža jednostavan način za zamjenu pojave riječi ili uzorka unutar niza. Isto vrijedi i za lokalizaciju. To ne znači da se to ne može učiniti sa standardnom XSLT sintaksom. Postoje načini, ali oni nisu ni približno tako jednostavni koliko bismo željeli. Ako stvarno želite pisati funkcije manipulacije tekstom pomoću rekurzivnih predložaka, budite moj gost.

Glavna slabost XSLT-a je obrada teksta, što se čini razumnim jer je njegova svrha generiranje XML-a. Međutim, budući da je XML sadržaj u potpunosti tekst, XSLT treba snažnije rukovanje tekstom. Nepotrebno je reći da dizajneri stilskih listova s ​​vremena na vrijeme zahtijevaju određenu proširivost. Uz Xalan, Java omogućuje ovu proširivost.

Koristite JDK klase unutar XSLT-a

Možda će vas obradovati činjenica da ne morate pisati nijedan Java kôd da biste iskoristili Xalanovu proširivost. Kada koristite Xalan, možete stvoriti i pozvati metode na gotovo bilo kojem Java objektu. Prije korištenja Java klase, morate joj osigurati XSLT prostor imena . Ovaj primjer deklarira "java"kao prostor imena za sve u ili ispod Java paketa (tj. Cijeli JDK):


  

Sad trebamo nešto poduzeti. Počnimo s malim XML dokumentom:

 Java može biti hir J. Burke 30.11.97  

Od vas je zatraženo da oblikujete ovaj XML tako da se naslov prikazuje velikim slovima. Programer koji je novi u XSLT jednostavno bi otvorio XSLT referencu kako bi potražio toUpper()funkciju; međutim, bila bi razočarana kad bi utvrdila da referenci nedostaje. translate()Metoda je vaš najbolji kladiti se, ali imam još bolju metodu: java.lang.String.toUpperCase(). Da biste koristili ovu metodu, morate instancirati Stringobjekt sa sadržajem naslova. Evo kako možete stvoriti novu Stringinstancu sa sadržajem naslovnog elementa:


  

nameAtribut određuje ručku na svoj novi Stringprimjer. Konstruktor pozivate tako da prvo navedete prostor imena zajedno s preostalom stazom do Stringklase. Kao što ste mogli primijetiti, Stringnedostaje new()metoda. Koristite new()za konstrukciju Java objekta u Xalanu; odgovara Javinoj newključnoj riječi. Argumenti dati za new()određivanje verzije konstruktora koja će biti pozvana. Sad kad imate sadržaj naslova unutar Java Stringobjekta, možete koristiti toUpperCase()metodu, i to tako:


  

To bi vam u početku moglo izgledati čudno. Kada koristite Java metode na određenoj instanci, prvi argument je instanca na koju želite da se metoda poziva. Očito je da Xalan koristi introspekciju kako bi pružio ovu sposobnost.

Ispod ćete pronaći još jedan trik. Evo kako možete odašiljati datum i vrijeme bilo gdje unutar vašeg lista stilova koristeći java.lang.Date:


  

Evo nečega zbog čega će svima biti potreban dan da lokalizira generičku tablicu stilova između dva ili više jezika. Možete koristiti java.util.ResourceBundleza lokalizaciju doslovnog teksta u tablici stilova. Budući da vaš XML ima oznaku autora, možda ćete htjeti ispisati "Author:"pored imena osobe.

Jedna od mogućnosti je stvaranje zasebne tablice stilova za svaki jezik, tj. Jedan za engleski, drugi za kineski itd. Problemi svojstveni ovom pristupu trebali bi biti očiti. Održavanje dosljednosti više verzija tablica stilova oduzima puno vremena. Također morate izmijeniti svoju aplikaciju tako da odabere ispravnu tablicu stilova na temelju korisničkog jezika.

Umjesto da duplicirate tablicu stilova za svaki jezik, možete iskoristiti Java-ove značajke lokalizacije. Lokalizacija uz pomoć ResourceBundledokaza dokazuje bolji pristup. Unutar XSLT-a, učitajte ResourceBundlena početku tablica stilova, otprilike ovako:


  

Predavanje ResourceBundleočekuje da će pronaći datoteku pozvanu General.propertiesu vašem CLASSPATH. Jednom kad se paket kreira, može se ponovno upotrijebiti u čitavom listu stilova. Ovaj primjer dohvaća authorresurs:


  

Opet primijetite neobičan potpis metode. Obično ResourceBundle.getString()uzima samo jedan argument; međutim, unutar XSLT-a također morate navesti objekt kojim želite pozvati metodu.

Napišite vlastita proširenja

U nekim rijetkim situacijama možda ćete trebati napisati vlastito proširenje XSLT, u obliku funkcije proširenja ili elementa proširenja. Razgovarat ću o stvaranju funkcije produženja, koncepta prilično lako shvatljivog. Bilo koja funkcija proširenja Xalan može uzeti nizove kao ulazne i povratne nizove u XSLT procesor. Vaša proširenja također mogu uzeti NodeLists ili Nodes kao argumente i vratiti ove vrste u XSLT procesor. Upotreba Nodes ili NodeLists znači da izvornom XML dokumentu možete dodati funkciju proširenja, što ćemo i učiniti.

Jedna vrsta tekstualne stavke koja se često susreće je datum; pruža izvrsnu priliku za novo XSLT proširenje. Naš je zadatak oblikovati element članka tako da se datum ispisuje u sljedećem formatu:

Petak, 30. studenog 200

Može li standardni XSLT popuniti gore navedeni datum? XSLT može završiti većinu zadatka. Utvrđivanje stvarnog dana je težak dio. Jedan od načina za brzo rješavanje tog problema je upotreba java.text.SimpleDateklase formata unutar funkcije proširenja za vraćanje niza oblikovanog kako želimo. Ali pričekajte: primijetite da se dan prikazuje podebljanim tekstom. To nas vraća na početni problem. Razlog zašto čak razmatramo funkciju proširenja je taj što izvorni XML dokument nije uspio strukturirati datum kao skup čvorova. Ako naša funkcija proširenja vrati niz, i dalje ćemo biti teško stilizirati polje dana drugačije od ostatka niza datuma. Evo korisnijeg formata, barem iz perspektive XSLT dizajnera:

  11. 30. 2001  

We now create an XSLT extension function, taking a string as an argument and returning an XML node in this format:

  November 30 Friday 2001  

The class hosting our extension function doesn't implement or extend anything; we will call the class DateFormatter:

public class DateFormatter { public static Node format (String date) {} 

Wow, too easy, huh? There are absolutely no requirements placed on the type or interface of a Xalan extension function. Generally, most extension functions will take a String as an argument and return another String. Other common patterns are to send or receive org.w3c.dom.NodeLists or individual Nodes from an extension function, as we will do. See the Xalan documentation for details on how Java types convert to XSLT types.

In the code fragment above, the format() method's logic breaks into two parts. First, we need to parse the date string from the original XML document. Then we use some DOM programming techniques to create a Node and return it to the XSLT processor. The body of our format() method implementation reads:

 Document doc = DocumentBuilderFactory.newInstance(). newDocumentBuilder().newDocument(); Element dateNode = doc.createElement("formatted-date"); SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, locale); df.setLenient(true); Date d = df.parse(date); df.applyPattern("MMMM"); addChild(dateNode, "month", df.format(d)); df.applyPattern("EEEE"); addChild(dateNode, "day-of-week", df.format(d)); df.applyPattern("yyyy"); dateNode.setAttribute("year", df.format(d)); return dateNode; 

dateNode will contain our formatted date values that we return to the stylesheet. Notice that we've utilized java.text.SimpleDateFormat() to parse the date. This allows us to take full advantage of Java's date support, including its localization features. SimpleDateFormat handles the numeric date conversion and returns month and day names that match the locale of the VM running our application.

Remember: the primary purpose of an extension function is simply to allow us access to existing Java functionality; write as little code as possible. An extension function, like any Java method, can use other methods within the same class. To simplify the format() implementation, I moved repetitive code into a small utility method:

private void addChild (Node parent, String name, String text) { Element child = parent.getOwnerDocument().createElement(name); child.appendChild(parent.getOwnerDocument().createTextNode(text)); parent.appendChild(child); } 

Use DateFormatter within a stylesheet

Now that we have implemented an extension function, we can call it from within a stylesheet. Just as before, we need to declare a namespace for our extension function:


  

Ovoga puta u potpunosti smo kvalificirali put do klase koja je domaćin funkcije proširenja. To nije obavezno i ​​ovisi o tome hoćete li koristiti druge klase u istom paketu ili samo jedan objekt proširenja. Puno možete proglasiti CLASSPATHprostorom imena ili upotrijebiti paket i odrediti klasu u kojoj se poziva funkcija proširenja. Određivanjem punog CLASSPATH, tipkamo manje kada pozivamo funkciju.

Da biste iskoristili funkciju, jednostavno je pozovite iz selectoznake, i to tako: