Am tot stat si m-am gandit zilele trecute cum sa explic in asa fel incat sa intelegeti acest framework mai usor si am ajuns la concluzia ca cel mai usor ar fi sa discutam pe o aplicatie.
Mai jos vedeti cum arata aplicatia in Designer, dupa care este este codul xml al aplicatiei.
Voi explica pe scurt ce face aceasta aplicatie, dupa codul xml. Cred ca daca aveti rabdare sa cititi acest post reusiti sa intelegeti cum functioneaza acest framework care este mult diferit de orice sunteti obisnuiti.
Cod: Selectaţi tot
<app outputxsl="xsl/aws2html.xsl">
<bookmarks/>
<client>
<content>
<table id="DOMtblIterator">
<tr>
<th class="first">
id
</th>
<th>
title
</th>
<th>
location
</th>
<th>
reference
</th>
</tr>
<tr unit="">
<td reference="id"/>
<td reference="name"/>
<td reference="location" skip=""/>
<td reference="location" modtype="prepend" skip="">
<button reference="id">
Button
</button>
</td>
</tr>
</table>
<import source="http://www.phpromania.net/forum/viewtopic.php?t=25914&sid=1c9cecdbb27156ece97cf5f58917f109" xpath="//table[@width='98%'][2]" importashtml=""/>
</content>
</client>
<templates>
<importtest>
<strong>
<font>
SESIUNEA:
<replace>
<?aws $el->setAttribute("color","red");
return session_id();?>
</replace>
</font>
</strong>
</importtest>
</templates>
<filters>
<dom>
<filter name="FILTRU IMPORT">
<import xpath="//app/templates/importtest/*"/>
//span[@class='catrowtext']
</filter>
<filter name="SCHIMBA USERUL MEU">
<nodelist>
//b[contains(.,'cezar.lucan')]
</nodelist>
<?aws $el->replace("
<strong>
XMS 2.0
</strong>
");?>
</filter>
<filter name="CAUTA ATTR CLASA">
<xpath>
//@class[contains(.,'row')]
</xpath>
<?aws $el->nodeValue = "TESTATTR";?>
</filter>
<filter name="EXEMPLU DOMITERATOR">
<domiterator>
//*[@id="DOMtblIterator"]
<norecords>
<?aws return '
<tr>
<td colspan="4">
No records
</td>
</tr>
';?>
</norecords>
</domiterator>
<?aws return array(array(id => "10",name => "john", location=>"Brasov",product=> "My Product"),array(id => "15",name => "io", location=>"Bucuresti",product=> "My Product"));?>
</filter>
</dom>
</filters>
</app>
In primul rand, orice aplicatie are urmatoarele parti:
- client/header - este de fapt html/head
- client/content - sau html/body
Cand XMS trimite spre client o aplicatie , va cauta atributul outputxsl al app si daca este gasit va folosi fisierul xsl dat de valoarea acestui atribut. In acest caz (aplicatie html), fisierul este xsl/aws2html.xsl.
Pentru a interactiona cu layout-ul, XMS are predefinite o serie de directive si filtre. In plus exista posibilitatea de a defini filtre, ce vor fi executate doar in aplicatia unde sunt definite sau in orice aplicatie.
Nu am vrut sa complic aplicatia dar totusi vreau sa va arat ce este o directiva un filtru si cum functioneaza.
Directiva: un element predefinit care poate sa fie oriunde in /app/client si XMS va cauta aceste directive apoi va executa in functie de cum a fost definita
Filtrul: un element in /app/filters/dom (filtre de tip DOM) sau /app/filters/ob (filtre de tip text) . XMS executa filtrul prin identificarea nodului tinta al sau si executarea codului (predefinit sau definit de utilizator) cu elementul tinta ca parametru.
Cod: Selectaţi tot
<import source="http://www.phpromania.net/forum/viewtopic.php?t=25914&sid=1c9cecdbb27156ece97cf5f58917f109" xpath="//table[@width='98%'][2]" importashtml=""/>
Cea mai des folosita directiva este
import. Aceasta directiva va citi fisierul dat de atributul source, cauta elementele din calea data de atributul xpath si se "inlocuieste" cu rezultatul.
import este in primul rand folosita pentru a importa cod XMS din aplicatii existente sau din aplicatia curenta (daca nu are atributul source). Deasemenea, import poate folosi ca sursa atat fisiere xml (default) sau html (daca are atributul importashtml).
In aplicatia de mai sus, in app/client/content este un exemplu de utilizare a acestei directive. Deci, import va deschide ca sursa html fisierul din atributul source (in acest exemplu este vorba chiar despre acest topic), cauta al 2-lea tabel care are atribut width=98%, si se inlocuieste cu rezultatul.
Bineinteles, se pot face multe operatii pe fiecare nod in parte, pe documentul sursa, chiar se pot shimba atributele directivei "on the fly" folosind "directiva copil"
runfirst. Mai multe exemple pe site.
Cod: Selectaţi tot
<replace>
<?aws $el->setAttribute("color","red");
return session_id();?>
</replace>
Directiva
replace (o gasiti in //app[1]/templates[1]/importtest[1]/strong[1]/font[1]/replace[1] - va fi importata in aplicatie si executata) primeste ca parametru nodul parinte al directivei si se inlocuieste cu rezultatul functiei.
In acest exemplu folosesc replace pentru a arata id-ul sesiunii dar si pentru a schimba culoarea textului. Cum parintele directivei replace este font, codul $el->setAttribute("color","red"); va schimba culoarea.
Functia din "replace" trebuie sa returnese intotdeauna o valoare!
Cod: Selectaţi tot
<filter name="FILTRU IMPORT">
<import xpath="//app/templates/importtest/*"/>
//span[@class='catrowtext']
</filter>
Acum ca am vazut cum lucreaza o directiva, sa explic cum functioneaza un filtru. In acest exemplu am folosit filtrul predefinit import, deoarece face exact ceea ce face directiva cu avantajul ca putem accesa elemente din
client "de la distanta".
Pentru ca am importat prima pagina a acestui topic, acum hai sa cautam un element in sursa topicului pe care sa il schimbam cu unul din aplicatia curenta.
Daca va uitati in codul aplicatiei, veti vedea ca filtrele sunt definite in /app/filters.
Asa cum am spus mai sus, orice filtru are un nod tinta: in acest exemplu este vorba de orice nod "span" care are clasa catrowtext (//span[@class='catrowtext']).
Filtrul import, va cauta span-ul de mai sus si il va inlocui cu nodul dat de atributul xpath al nodului import.
Acest exemplu de filtru ne arata cum filtrul import poate fi folosit pentru a importa cod XML din aplicatia curenta. Daca vreti sa importati cod dintr-o alta aplicatie, atunci in atributul source al import puteti sa setati care este acea aplicatie.
Cod: Selectaţi tot
<filter name="SCHIMBA USERUL MEU">
<nodelist>
//b[contains(.,'cezar.lucan')]
</nodelist>
<?aws $el->replace("
<strong>
XMS 2.0
</strong>
");?>
</filter>
Continuam cu explicarea filtrului
nodelist. Folosesc acest filtru pentru a schimba id-ul meu din pagina cu textul XMS 2.0. Deci cauta in pagina un element
b care contine textul cezar.lucan.
nodelist apeleaza functia cu parametrul $el care este de tip awsXML. Metodele aceste clase sunt oarecum similare cu jQuery.
Cod: Selectaţi tot
<filter name="CAUTA ATTR CLASA">
<xpath>
//@class[contains(.,'row')]
</xpath>
<?aws $el->nodeValue = "TESTATTR";?>
</filter>
Urmatorul filtru este
xpath. Acest filtru primeste ca parametru fiecare element al interogarii, deci executa codul pentru fiecare element din xpath, in parte.
Putem executa functia pe orice tip de nod, in acest caz am ales sa caut toate atributele din pagina, care au numele "class" si contin textul "row".
Dupa cum vedeti mai sus, schimb valoarea fiecarui atribut gasit, cu "TESTATTR".
Daca vrei sa cautati un element atunci in xpath puneti //nume_elem[@numeatribut="valoare"] sau orice alta interogare aveti nevoie. Puteti cauta chiar si comment-urile sau noduri de tip processing instruction sau direct text (//comment() sau //processing-instruction("target") sau //text() .......)
Cod: Selectaţi tot
<filter name="EXEMPLU DOMITERATOR">
<domiterator>
//*[@id="DOMtblIterator"]
<norecords>
<?aws return '
<tr>
<td colspan="4">
No records
</td>
</tr>
';?>
</norecords>
</domiterator>
<?aws return array(array(id => "10",name => "john", location=>"Brasov",product=> "My Product"),array(id => "15",name => "io", location=>"Bucuresti",product=> "My Product"));?>
</filter>
Ultimul filtru pe care am ales sa il pun in aplicatie, este
domiterator. Acesta este in primul rand pentru a fi folosit pt lucrul cu bazele de date (exemplu pe site).
domiterator ia ca obiect de lucru un sir de siruri asociative, caut in nodul tinta un element care are atributul unit, pe care il multiplica pentru fiecare array.
Pentru a utiliza valorile din acest sir asociativ, domiterator cauta in fiecare "unit" elementele care au atributul "reference" identic cu numele fiecarei etichete..... Da, stiu, suna complicat dar este chiar foarte simplu!!!
Pentru a intelege, in nodul client. gasiti tabelul:
Cod: Selectaţi tot
<table id="DOMtblIterator">
<tr>
<th class="first">
id
</th>
<th>
title
</th>
<th>
location
</th>
<th>
reference
</th>
</tr>
<tr unit="">
<td reference="id"/>
<td reference="name"/>
<td reference="location" skip=""/>
<td reference="location" modtype="prepend" skip="">
<button reference="id">
Button
</button>
</td>
</tr>
</table>
Mai sus vedeti ca a doua linie are atributul "unit".
In unit puteti vedea cum fiecarui element pe care vreau sa il modific, ii setez atributul reference cu valoarea unei etichete din sir.
Default, domiterator schimba continutul fiecarei referinte cu valoarea corespunzatoare din sir. Se poate modifica comportamentul pentru fiecare label, pentru cele care vrem doar, putem accesa elementele DOM direct pentru a seta atribute, toate aceste prin folosirea filtrelor copil (lista este pe site). Exemplu complet al filtrului, cu mare parte din optiuni mai jos (arata si folosirea PDO pt o baza de date):
Cod: Selectaţi tot
<filter>
<domiterator>
//*[@id="DOMtblIterator"]
<eachreference>
<?aws $el->setAttribute("WORKS",$label."=".$value);
$el->setAttribute("recordsetTEST",$recordset["name"]);?>
</eachreference>
<eachnamedreference>
<id>
<!--There are two elements referencing to "id" field; this is how you can access these DOM elements and modify them directly from php; --><!--function parameters: $el,$label,$value,$recordset where $el is the DOMNode, $label is the name of the field, $value is the value of the field, $recordset is entire recordset (like array(name => "john", location=>"My City",product=> "My Product"))--><?aws $el->setAttribute("EACHNAMEDREFERENCE","WORKS FOR ID");
if($el->nodeName =="button") $el->appendChild($el->ownerDocument->createTextNode(" / I am a ".$el->nodeName));
else
$el->appendChild($el->ownerDocument->createTextNode(" / I am not a button, I am a ".$el->nodeName));?>
</id>
<name>
<!--function parameters: $el,$label,$value,$recordset where $el is the DOMNode, $label is the name of the field, $value is the value of the field, $recordset is entire recordset (like array(name => "john", location=>"My City",product=> "My Product"))--><?aws $el->setAttribute("EACHNAMEDREFERENCE","WORKS FOR NAME");
$el->setAttribute("anotherRecordsetTEST",$recordset["location"]);?>
</name>
<location>
<!--function parameters: $el,$label,$value,$recordset where $el is the DOMNode, $label is the name of the field, $value is the value of the field, $recordset is entire recordset (like array(name => "john", location=>"My City",product=> "My Product"))--><?aws $el->setAttribute("EACHNAMEDREFERENCE","WORKS FOR LOCATION");?>
</location>
</eachnamedreference>
<norecords>
<?aws return '
<tr>
<td colspan="4">
No records
</td>
</tr>
';?>
</norecords>
</domiterator>
<!--here we have to retrieve the data from our DB and give it to domiterator to be displayed; see "Content of filter" above --><?aws return $GLOBALS["APPINIT"]["PDO"]->query("select * from domiteratortest limit 0,3")->fetchAll(PDO::FETCH_ASSOC);?>
</filter>
Sunt multe alte exemple pe care le putem discuta. Daca aveti intrebari... nu ezitati, raspund la toate!
Pentru fiecare directiva si filtru gasiti exemple pe site. Daca este ceva neclar, scrieti aici si raspund cu placere!
Astept critici, comentarii, dar cel mai important.... sper ca acest post sa va starneasca curiozitatea si sa fi inteles structura si puterea acestui framework!