Conceptul de șabloane de proiectare a fost introdus de Erich Gamma, Richard Helm, Ralph Johnson si John Vlissides în cartea "Șabloane de proiectare: Elemente de software reutilizabil orientat pe obiect". Ideea principală era aceea de a avea la dispoziție un repertuar de tehnici care să poată fi refolosite. Cartea prezintă cele mai folosite 23 de șabloane specializate pentru programarea orientată obiect.
Mulți designeri de XSLT au încercat să păstreze particularitățile fișierelor HTML pentru a putea face transformările accesibile și celor neobișnuiți cu programarea.
Sunt multe feluri în care am putea să afișăm datele respective; de exemplu, am putea folosi grafice SVG, arbori realizați prin JavaScript sau doar liste indentate. Dintre acestea alegem reprezentarea prin tabele, în care vom avea câte un rând pentru fiecare persoană, rând împărțit în trei coloane cuprinzând numele, titlul și șeful persoanei respective.
Succesul acestui șablon de proiectare este acela ca foaia de stiluri să aibe aceeași structură ca rezultatul pe care dorim să-l obținem. Conținutul fix îl includem direct în foaia de stiluri, în timp ce conținutul variabil este introdus prin folosirea instrucțiunilor <xsl:value-of>. Pentru anumite secțiuni care se repetă, cum ar fi rândurile într-o tabelă sau într-o listă, putem folosi instrucțiuni ca <xsl:for-each>, <xsl:if> sau <choose>.
Acest fel de foi de stiluri folosesc foarte puțin din puterea XSLT-ului, dar sunt foarte ușor de învățat de persoane care au experiență în HTML, chiar dacă nu au experiență în programare. Acest lucru merită a fi considerat, deoarece multe site-uri web au nevoie de schimbări de aspect și astfel acest lucru este mai ușor de realizat dacă editorii de conținut pot să realizeze singuri această schimbare.
O singură restricție ar fi aceea ca input-ul să provină dintr-un document XML, deși de cele mai multe ori provine dintr-o bază de date relațională. În acest caz este indicat să se folosească procesări care să lucreze direct pe un arbore DOM, sau pe un flux de evenimente SAX, fără a avea nevoie de un document XML ca format intermediar.
Foile de stiluri navigaționale derivă direct din foile de stiluri completează-spațiile-lipsă, fiind deasemeni orientate-rezultat. Totuși acestea sunt mai complicate necesitând utilizarea șabloanelor cu nume folosite ca subrutine pentru generarea sarcinilor întâlnite, a variabilelor folosite pentru a calcula valori necesare în mai multe locuri, sau a sortărilor, parametrilor sau cheilor.
Dacă o foaia de stiluri completează-spațiile-lipsă arată ca un HTML îmbunătățit cu câteva instrucțiuni de control, o foaie navigațională se aseamănă cu un program convențional procedural care are variabile, blocuri condiționale și apeluri de subrutine.
Foile de stiluri navigaționale sunt de obicei folosite pentru a produce rapoarte pentru documente XML orientate-date, unde structura sursei documentului este regulară și anticipabilă.
foaia de stiluri asociată realizează un raport referitor la numărul de vânzări pentru fiecare editură.
Definim o variabilă globală $edituri care va cuprinde elementele <editură> distincte intalnite in document.
Asocierea foii de stiluri va genera rezultatul:
Diferența între foaia de stiluri navigațională și foaia de stiluri completează-spațiile-lipsă este aceea că elementele <xsl:stylesheet> și <xsl:template> sunt acum explicite, ceea ce dă posibilitatea introducerii unor elemente ca <xsl:key> și <xsl:variable>. În plus, foaia de stiluri navigațională a depășit limita de a mai fi un document HTML cu instrucțiuni de control și a devenit un adevărat program. Totuși această limită este superficială astfel încât persoane care se descurcă cu foi de stiluri completează-spațiile-lipsă să poată înțelege și foi de stiluri de acest fel.
Deși utilizarea instrucțiunilor de control de genul <xsl:if>, <xsl:call-template> și <xsl:for-each> dau foii de stiluri un aspect procedural, ele nu contrazic conceptul că XSLT este un limbaj declarativ. Acest lucru este posibil datorită faptului că instrucțiunile nu trebuiesc executate în ordinea în care au fost scrise - variabilele nu pot fi actualizate astfel încât rezultatul unei instrcțiuni nu poate să afecteze evoluția următoarei instrucțiuni. De exemplu, ne putem ușor imagina evoluția instrucțiunii <xsl:for-each> pe acest exemplu, procesând nodurile selectate din document și adăugându-le una câte una în arborele rezultat, dar ar fi la fel de valid dacă această procesare s-ar face în ordine inversă sau paralelă, atât timp cât nodurile sunt adăugate în arbore pe poziția lor corespunzătoare. Din această cauză acest șablon se numește navigațional și nu procedural. Este navigațional pentru că trebuie să știm exact unde putem găsi nodurile în arborele pe care îl procesăm, și nu este procedural, pentru că nu putem defini această ordine de vizitare a nodurilor.
O foaie de stiluri este formată din reguli prin care se descrie felul în care sursa va fi procesată, în genul "dacă se găsește un element <specie>, acesta trebuie să fie afișat în italics". Putem afirma că această abordare este una firească pentru limbajul XSLT, intenția principală pentru care acesta a fost creat, totuși nu și singura.
Spre deosebire de foile de stiluri navigaționale, o foaie de stiluri bazată pe reguli nu e structurată conform cu rezultatul dorit. De fapt, face presupuneri minimale asupra structurii sursei sau rezultatului, prezentându-se mai degrabă ca un inventar de componente care ar putea fi întâlnite în sursa documentului, aranjate într-o ordine arbitrară.
Foile de stiluri bazate pe reguli se folosesc atunci când este nevoie să procesăm documente cu o structură flexibilă și care se actualizează des, sau când avem de procesat aceleași elemente în documente separate.
Foile de stiluri bazate pe reguli sunt asemănătoare foilor de stiluri CSS. În CSS putem defini o regulă de forma "pentru un anumit set de elemente, se va aplica un stil specific". În XSLT, regulile devin mult mai flexibile: șabloanele pe care le putem folosi pentru a defini elementele care trebuiesc procesate pot fi mult mai complexe și raza de acțiune a acestora poate fi mult mai largă.
O foaie de stiluri bazată pe reguli simplă va conține câte o regulă pentru fiecare tip de element. Regula va specifica forma rezultatului în format HTML și apoi va apela <xsl:apply-templates> pentru a putea procesa copii nodului respectiv. Asta are ca efect copierea în rezultat a nodurilor text și posibilitatea procesării nodurilor copii în funcție de propria regulă șablon.
De obicei, foile de stiluri bazate pe reguli creează un arbore rezultat foarte asemănător cu structura arborelui sursă și majoritatea textului apare în aceeași ordine în care a fost declarat, dar fiind imbricat de alte etichete. Totuși asta nu înseamnă că procesarea trebuie să fie pur secvențială. Se pot procesa de mai multe ori aceleași bucăți de arbore, se pot rearanja nodurile arborelui, se poate prelua informația din noduri părinte, toate astea fără a strica design-ul șablonului bazat pe reguli.
Trăsătura caracteristică foilor de stiluri bazate pe reguli este aceea că conține câte un șablon de procesare pentru fiecare tip de obiect găsit în document. Se pot combina mai multe șabloane de proiectare, mai ales dacă documentul sursă conține structuri atât orientate-document, cât și orientate-înregistrare. Șablonul navigațional se poate folosi pentru structuri regulate, iar cel bazat pe reguli pentru structuri mai puțin regulate. Cu cât o foiae de stiluri este mai complicată și mai dezvoltată, cu atât crește probabilitatea ca aceasta să conțină mai multe șabloane de proiectare.
Foile de stiluri computaționale sunt cele mai complexe dintre cele patru șabloane de proiectare. Sunt folosite în momentul în care este nevoie să se genereze noduri în arborele rezultat care nu au corespondență directă cu nodurile din arborele sursă. Acest lucru se întâmplă când avem structuri în sursă care nu sunt ecplicite. De exemplu:
Alte exemple apar când dorim să organizăm datele în rânduri și coloane, dar ele nu sunt inițial în această formă, sau când dorim să realizăm agregări de date, cum ar fi construcția unui tabel general din date care dețin numai informații individuale.
Foile de stiluri computaționale devin dificil de implementat deoarece XSLT nu dispune de instrucțiune de asignare și nu putem realiza instrucțiuni repetitive în modul în care eram obișnuiți în alte limbaje de programare.
Stilul de a scrie cod fără a folosi instrucțiunii de asignare se numește Programare Funcțională. Fără asignare, putem procesa instrucțiuniile în orice ordine, pentru că rezultatul unei instrucțiuni nu mai depinde de starea unei instrucțiuni anterioare.
Principalul motiv pentru care un limbaj funcțional este considerat ideal pentru un limbaj ca XSLT este abilitatea de a realiza lucrurile incremental, în paralel sau în orice ordine.
În continuare prezentăm câteva din cele mai bune practici și șabloane care trebuiesc urmate atunci când scriem foi de stiluri XSL:
Singura operație pe mulțimi pusă la dispoziție de XSLT este reuniunea și poate fi specificată folosind operatorul "|" în XPath și XSLT. Este posibilă construirea intersecției a două noduri-mulțime în XPath pur. Această tehnică a fost descoperită de Michael Kay și este cunoscută ca "metoda Kaysiană".
Exemplu:
Rezultatul va fi:
Această metodă arată o modalitate de a evita recursia la implemetarea buclelor în XSLT.
Rezultatul va fi:
Cu alte cuvinte se dorește crearea de noi noduri, numărul acestora fiind în funcție de o valoare *value* conținuta în document. Mai jos, este prezentată o mică generalizare care este independentă de numărul de noduri din documentul sursă XML, folosindu-se numărul de noduri din foaia de stil:
Aici se foloseste capacitatea foii de stil doar pentru nodurile element. Această capacitate va fi incrementată considerabil dacă se testează mai multe tipuri de noduri, cum ar fi următoarele:
unde $st a fost definit ca ('') pentru document -- ceea ce este de fapt rădăcina foii de stil.
Abilitatea XPath de a selecta un set de noduri bazată pe condiții complexe este foarte puternică. Totusi, minimalizează capabilitatea de a specifica un șir ca fiind opusul unui set de noduri. Deseori, trebuie folosită o construcție complicată de tip multi-linie xsl:choose doar pentru a specifica că "în cazul1 folosește șir1, în cazul2 folosește șir2,..., în cazulN folosește șirN".
În toate aceste cazuri se simte nevoia unei tehnici, care ar permite specificarea unui șir într-o singură expresie XPath, care depinde de condiție/condiții.
Iata solutia acestei probleme: Se doreste o expresie XPath, care returneaza un sir cand anumite conditii sunt adevarate, și intoarce sirul gol daca aceleași condiții sunt false. Fals poate fi reprezentat de "0", iar adevărat de "1". Ce funcție care opereaza cu șiruri poate fi folosită pentru a reprezenta aceste două valori? substring() pare a fi convenabilă. Și iată trucul: se foloseste substring() cu doua argumente: substring(str, nOffset) care va intoarce bucata de șir str care face parte din multimea de sufixe ale lui nOffset.
În particular: substring(str,1) returnează întregul șir substring(str, nVeryLargeNumber) va întoarce șirul vid dacă nVeryLargeNumber este mai mare decât lungimea oricărui posibil șir.
Astfel, expresia pe care o vom folosi: concat(substring(str1,exp(Condition)),substring(str2,exp(not(Condition))), și se dorește ca exp(Condition) să fie 1 dacă Condition este adevarată și să fie infinit dacă Condition este falsă.
Se definește exp(Condition) astfel:
1 div Condition deoarece o expresie booleană este mai întâi convertită la un număr (adevarat->1, fals->0)
exp(adevarat) = 1
exp(fals) = infinit.
Expresia XPath care întoarce str1 dacă Cond este adevarată și str2 dacă aceeași condiție este falsă, este următoarea: concat(substring(Str1,1 div Cond),substring(Str2,1 div not(Cond))).
Se dorește generarea textului "My department" cu ajutorul unui template, atunci când este pasat un parametru "IT", și generarea textului "Some other department", dacă valoarea parametrului nu este "IT". Nu este permisă utilizarea xsl:if sau xsl:when. Iată codul:
Gruparea este deseori ineficient implementată în XSL. Bazele de date ofera de obicei rezultate structurate, în functie de înregistrarile pe care le conțin. De exemplu, se consideră un tabel ce reprezintă angajați și retunează următorul XML:
Problema este cum să transformăm această intrare într-un număr de liste grupate pe departamente pentru ca ieșirea sa arate astfel:
Sunt doi pași pentru a ajunge la soluție:
O metoda ar fi urmatoarea:
Metoda Muenchiană a fost dezvoltată de Steve Muench pentru a crea functii mai eficiente pentru astfel de grupări, folosind chei. Acestea funcționează atribuind o valoare-cheie unui nod și dând posibilitatea accesului cu ușurință la nodurile care au aceeași valoarea-cheie. Efectiv, aceasta înseamna că daca se dorește gruparea unui set de noduri în conformitate cu o proprietate particulară a nodului, se pot folosi chei pentru a le grupa.
În exemplul anterior, trebuie grupați angajații pe departamente, așa că dorim sa atribuim fiecărui angajat o cheie cu valoarea corespunzătoare departamentului din care face parte. Nodurile pe care le vom grupa sunt cele date de atributul "match", iar valoarea cheii este dată de atributul "use":
Odată definită această cheie, dacă se cunoaste departamentul, se pot accesa repede toți angajatii care fac parte din acesta. De exemplu, key("employees-by-department", "IT") va furniza toate inregistrările care conțin departamentul "IT".
Primul lucru care trebuia făcut era identificarea departamentelor. Aceasta se poate face tot cu ajutorul cheilor. Se va folosi următoarea tehnică:
Odată identificate grupurile, acestea se pot sorta în orice ordine. Similar, se pot sorta și nodurile din grupurile respective. Iată un șablon care creează ieșirea dorită, specificată anterior:
Metoda Muenchiană este de obicei cea mai bună metodă de a grupa noduri din surse XML, deoarece nu implică interogarea unui numar mare de noduri și este astfel mai eficientă. Beneficiul acestei metode este acela că ieșirea se poate modela ierahic, pe grupuri. Se poate aplica în orice situație în care se dorește gruparea nodurilor în functie de o anumită proprietate a unui nod ce este primit prin intermediul XPath. Partea intrinsecă este aceea că metoda Muenchiană poate fi aplicată numai daca procesorul XSLT suportă cheile. Ca adăugare, folosirea cheilor poate sa foloseasca multa memorie, deoarece toate nodurile și cheile aferente trebuie păstrate în memorie. În final, utilizarea cheilor poate fi destul de complicată acolo unde nodurile pe care doriți sa le grupați sunt împrăștiate în diferite documente-sursă.