CATEGORII DOCUMENTE |
Java si XML
Fisiere XML in aplicatii Java
Prelucrarea si generarea de documente XML in programe Java sunt operatii tot mai uzuale datorita aplicatiilor cum ar fi: serializare continut obiecte si apeluri de proceduri la distanta, transmiterea de mesaje intre calculatoare (mesaje SOAP), fisiere de configurare, fisiere descriptor de componente Java ("deployment descriptor"), fisiere "build" folosite de programul "ant" pentru construire si instalare de aplicatii, s.a. Incepand cu versiunea 4 clasele Java pentru aplicatii XML au devenit standard si s-au extins, in pachete ca "javax.xml", "org.xml" si "org.w3c".
Mediile integrate de dezvoltare Java includ editoare de XML si permit verificari asupra sintaxei XML.
Standardele formale sau impuse de practica (SAX, DOM, StAX s.a.) constituie si exemple de programare la nivel de interfata, aratand cum un API poate fi definit numai din interfete Java, fara nici o referire la o clasa concreta.
Limbajul XML ("Extensible Markup Language") este un limbaj cu marcaje ("tag" va fi tradus aici prin "marcaj") extensibil, in sensul ca multimea de marcaje folosite poate fi definita in functie de tipul aplicatiei si nu este fixata dinainte (ca in HTML). Marcajele au rolul de a descrie datele incadrate de marcaje, deci semnificatia sau modul de interpretare a acestor date (si nu modul de prezentare, ca in HTML). Un fisier XML este un fisier text care contine marcaje; un marcaj este un sir intre paranteze unghiulare ('<' si '>').
Un prim exemplu este un mic fragment dintr-un fisier XML lista de preturi:
<priceList>
<computer>
<name> CDC </name>
<price> 540 </price>
</ computer >
<computer>
<name> SDS </name>
<price> 495 </price>
</ computer >
</priceList>
Un element este fragmentul cuprins intre un marcaj de inceput si un marcaj de sfarsit:
<price> 540 </price>
Un element are un nume (acelasi cu marcajul de inceput) si poate avea mai multe atribute si un continut; continutul poate include un text sau alte elemente sau elemente si text. Un element poate contine alte elemente, pe oricate niveluri de includere. In afara marcajelor pereche (start - end) pot exista si marcaje singulare de forma <tag/>.
Un marcaj de element gol ("empty element tag") este o prescurtare pentru cazurile in care nu exista caractere intre "start tag" si "end tag"; astfel <timestmp/> este o prescurtare pentru <timestmp> </timestmp>
Marcajele de inceput sau singulare pot fi insotite de atribute; fiecare atribut are un nume si o valoare. Exemple:
<computer type ="desktop"> . . . </ computer >
<computer name="SDS" price="495" />
Asa cum se vede din ultimul exemplu, proprietatile unor entitati (cum sunt numele si pretul unui produs) pot fi transmise fie ca atribute ale marcajului ce specifica entitatea, fie ca elemente incluse intre marcajele ce definesc o entitate.
Multimea marcajelor folosite intr-un document XML si relatiile dintre ele sunt definite intr-un fisier "schema" XML, folosit la validarea fisierelor XML care folosesc aceste marcaje. Se folosesc doua tipuri de fisiere schema: fisiere DTD (Document Type Definition) si fisiere XSD (XML Schema Definition). Exemplu de fisier DTD pentru lista de preturi:
<!ELEMENT priceList (computer)+>
<!ELEMENT computer (name, price) >
<!ELEMENT name (#PCDATA) >
<!ELEMENT price (#PCDATA) >
PCDATA ("Parsed Character Data") este un alt nume pentru siruri de caractere care trebuie luate in considerare de parser (spre deosebire de tipul CDATA).
Fisierul XSD este un fisier XML care foloseste marcaje predefinite si ofera mai multe posibilitati decat fisierul DTD in descrierea multimii de marcaje.
Pentru a permite utilizarea de marcaje cu acelasi nume in scheme diferite s-a introdus si in XML conceptul "spatiu de nume": un spatiu de nume contine marcaje distincte si este declarat la inceputul unui fisier schema. Daca intr-un acelasi fisier XML se folosesc marcaje din mai multe spatii de nume, atunci numele de marcaje trebuie prefixate de un simbol asociat spatiului de nume.
Exemplu de mesaj (cerere la un serviciu Web) in protocolul SOAP :
<SOAP-ENV:Envelope
xmlns:SOAP-ENV='https://schemas.xmlsoap.org/soap/envelope/'
SOAP-ENV:encodingStyle='https://schemas.xmlsoap.org/soap/encoding/'>
<SOAP-ENV:Body>
<m:GetLastTradePrice
xmlns:m='Some-URI'>
<symbol>MOT</symbol>
</m:GetLastTradePrice>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
In exemplul anterior se folosesc doua prefixe pentru spatii de nume: SOAP-ENV si "m"; primul are precizata adresa Web (URI) unde este definit, dar locul unde este definit"m" nu este precizat.
Un parser XML este un analizor de documente XML, care poate permite si crearea de noi documente XML prin program.
Un document XML este o instantiere a unei scheme, asa cum un obiect este o instantiere a unei clase. Se pot defini clase corespunzatoare elementelor XML, iar trecerea intre fisiere XML si clase Java (in ambele sensuri) este asigurata de clasele din interfata API numita JAXB (Java XML Binding). Clasele Java sunt generate pe baza unei scheme XML (de obicei un fisier DTD).
Un parser XML primeste ca intrare un fisier XML, verifica utilizarea corecta a marcajelor si (optional) face o validare fata de fisierul DTD sau XSD specificat. Un fisier XML bine format ("well formed") are toate perechile de marcaje incluse corect, la fel cum incluse perechile de paranteze dintr-o expresie sau perechile de acolade din Java. Exemple de erori de utilizare a marcajelor semnalate de un parser:
<a> . <b> . </a> . </b> (corect este <a>.<b>.</b>..</a>)
<a> . <b> . </b> . </c>
Validarea XML necesita specificarea unui fisier schema (DTD sau XSD) la inceputul documentului XML si inseamna certificarea faptului ca au fost folosite numai marcajele din schema, cu relatiile, atributele si tipurile de date descrise in schema. Validarea mareste timpul de analiza si este inutila atunci cand fisierele XML sunt generate de catre programe si nu sunt editate manual.
Datele dintr-un fisier XML si relatiile dintre ele constituie un "infoset", care poate fi reprezentat fie printr-un fisier text (XML), fie printr-un arbore in memorie, fie ca o secventa de evenimente XML. Elementele unui infoset sunt atomi XML: marcaje (de inceput, de sfarsit si goale), atribute folosite in marcaje, caractere intre marcaje (date si spatii albe), comentarii XML, instructiuni de prelucrare, s.a.
Un parser XML respecta o interfata cu aplicatiile (API), adica o serie de interfete Java care trebuie implementate de programul parser si sunt folosite de aplicatii pentru acces la datele furnizate de parser.
Problema principala in proiectarea unui parser XML este aceea ca el trebuie sa informeze aplicatia despre marcajele, atributele si celelalte elemente de infoset intalnite, dar actiunile declansate de aceste "evenimente" sunt specifice fiecarei aplicatii si nu fac parte din programul parser. In principiu exista doua categorii mari de programe parser, dupa modul cum prezinta rezultatul analizei:
- Parsere orientate document, care creeaza in memorie o structura de date ierarhica (un arbore) cu structura si continutul fisierului XML pe care o transmite aplicatiei. Standardul DOM ("Document Object Model") defineste interfata API pentru accesul aplicatiilor la arborele creat de parser, sub forma unor interfete Java.
- Parsere in flux continuu ("streaming parsers"), care informeaza aplicatia imediat ce se intalneste un element semnificativ. Aceste parsere sunt si ele de doua tipuri: cu apelare de metode "callback" din aplicatie de catre parser ("push parsers") sau cu extragere de informatii despre fisierul XML prin apelarea de catre aplicatie a unor metode din parser ("pull parsers"). Un parser "push" (de exemplu SAX ) detine controlul procesului de analiza XML si ofera aplicatiei informatii pe masura ce parcurge documentul XML. In cazul unui parser "pull" (de exemplu StAX) aplicatia detine controlul si cere programului parser informatii despre urmatorul element de limbaj din documentul analizat. Abrevierile SAX ("Simple API for XML") si StAX ("Streaming API for XML") se refera la standardizarea comunicarii dintre aplicatii si parser (prin interfete in Java).
Evenimentele SAX sunt produse de intalnirea unui atom XML (marcaj, atribut, sir dintre marcaje etc.). Un parser bazat pe modelul DOM are ca principal dezavantaj memoria necesara pentru arborele corespunzator unui document XML mai mare, mai ales ca in acest arbore apar noduri si pentru spatiile albe folosite la indentare si la fiecare linie noua. Toate spatiile albe consecutive dintre doua marcaje formeaza un singur atom XML, de acelasi tip cu alte siruri de caractere dintre marcaje succesive.
De obicei spatiile albe sunt introduse (la editarea manuala) numai pentru aspect si nu sunt semnificative; de aceea ele sunt ignorate de aplicatii in majoritatea cazurilor.
De exemplu, fisierul lista de preturi poate apare si sub forma urmatoare:
<!DOCTYPE priceList SYSTEM 'priceList.DTD'>
<priceList> <computer><name>CDC</name><price>540</price></computer>
<computer><name>SDS</name><price>495</price> </ computer ></priceList>
O alta critica adusa modelului DOM este aceea ca interfata API nu este total in spiritul orientarii pe obiecte si nu foloseste clasele colectie si iterator din Java. De aceea s-au propus si alte variante de modele arbore : JDOM si DOM4J ('J' de la Java).
Avantajul unui parser care creeaza un obiect arbore este acela ca permite operatii de cautare, de modificare in arbore si de creare a unui alt document XML din arbore.
Un parser SAX sau StAX este mai rapid, consuma mai putina memorie si este mai usor de folosit (nu necesita navigarea printr-un arbore), dar nu permite operatii repetate de cautare in document intr-un mod eficient. Este util atunci cand o aplicatie este interesata numai de anumite sectiuni dintr-un document XML si nu de intreg continutul. Modelul SAX nu permite crearea sau modificarea de documente XML prin program, dar modelul StAX permite aceste operatii.
Un alt standard, materializat intr-un API Java, este XSLT (XML Stylesheet Language for Transformation), care permite specificarea unor transformari asupra unui document XML in vederea conversiei sale intr-un alt format (de ex. HTML). Un obiect convertor ("transformer") primeste la creare un obiect sursa si un obiect rezultat, iar metoda "transform" face transformarile necesare de la sursa la rezultat.
Interfetele "Source" si "Result" sunt implementate de clase "DOMSource" si "DOMResult", "SAXSource" si "SaxResult" sau "StreamSource", "StreamResult" (fluxuri de intrare-iesire ca sursa si rezultat al transformarii). In felul acesta se poate trece intre diferite reprezentari posibile ale documentelor XML, cu sau fara modificari in continutul documentelor.
SAX (Simple API for XML) a fost primul API pentru XML si nu este un standard oficial, dar este utilizat si in prezent. De fapt, multe programe parser DOM au fost scrise pe baza unor parsere SAX .
Un parser SAX citeste un fisier XML, detecteaza eventuale erori formale si arunca exceptii, dar in principal apeleaza anumite metode cu nume si prototip ce depind de tipul elementului de infoset recunoscut in fisier.
Metodele din aplicatie apelate de un parser SAX sunt grupate in cateva interfete (ContentHandler, DTDHandler, ErrorHandler), definite in pachetul org.xml.sax, dintre care numai ContentHandler este importanta atunci cand nu se cere si validarea fata de un DTD. Principalele metode "callback" din aceasta interfata sunt:
// apelata la inceput de element (marcaj de inceput)
public void startElement (String uri, String localName,String qName, Attributes atts)
throws SAXException;
// apelata la sfarsit de element (marcaj de terminare)
public void endElement (String uri, String localName, String qName)
throws SAXException;
// apelata la detectarea unui sir de caractere
public void characters (char ch[ ], int start, int length)
throws SAXException;
Parametrul "uri" indica locatia unde este definit spatiul de nume pentru acest tag, iar "qName" ("qualified name") este numele complet, prefixat de identificatorul spatiului de nume; daca nu este specificat un spatiu de nume (uri este un sir vid), atunci "qName" este numele de tag si nu "localName"(care este tot un sir vid).
Interfata Attributes corespunde unei liste si are metode ca: getLength, getQName(int), getValue(int). Exemplu de extragere si afisare atribute:
public void startElement(String uri, String aName, String qName, Attributes atts)
throws SAXException
// metode din DefaultHandler redefinite (metode callback)
// un marcaj de inceput element
public void startElement(String namespaceURI,String sName,String qName,
Attributes attrs) throws SAXException
}
System.out.println (sb.append ('>'));
sp+=' '; // creste indentare dupa un marcaj de inceput
}
// un marcaj de sfarsit element
public void endElement(String namespaceURI, String sName, String qName )
throws SAXException
// un sir de caractere delimitat de marcaje
public void characters(char buf[], int offset, int len)throws SAXException
}
Metoda "parse" are ca rezultat un obiect de tip Document, care este arborele creat pe baza documentului XML, conform modelului DOM.
CDC 540 SDS 495
De fapt, orice arbore DOM mai are un nivel radacina (nefigurat aici) care corespunde intregului document XML (nod cu numele "#document" si valoarea null).
Fiecare nod dintr-un arbore DOM are un nume, o valoare si un tip. Tipurile sunt numere intregi, dar exista si nume mnemonice pentru aceste tipuri. Exemple de constante din interfata Node:
public static final short ELEMENT_NODE = 1;
public static final short ATTRIBUTE_NODE = 2;
public static final short TEXT_NODE = 3;
public static final short DOCUMENT_NODE = 9;
Nodurile cu text au toate acelasi nume ("#text"), iar valoarea este sirul de caractere ce reprezinta textul. In exemplul anterior cele 4 noduri terminale sunt noduri text (cu valorile "CDC","540","SDS","495"). Parserul DOM creeaza noduri text si pentru grupuri de spatii albe (blancuri sau terminator de linie inainte sau dupa un marcaj). Pentru fisierul XML cu 10 linii si indentare numarul de noduri din arborele DOM este 20 : 1 pe nivelul 1, 5 pe nivelul 2, 10 pe nivelul 3 si 4 pe nivelul 4. Dintre acestea sunt 9 noduri text cu spatii albe (3 pe nivelul 2 si 6 pe nivelul 3).
Nodurile pentru elemente au numele marcajului si valoarea null. In arborele de mai sus am scris numele nodurilor de pe primele 3 niveluri (de tip 1) si valorile nodurilor de pe ultimul nivel (de tip 3).
Modelul DOM defineste mai multe interfete Java, implementate de parser si folosite de catre aplicatii :
- Interfata Node contine metode de acces la un nod de arbore DOM si la succesorii sai, dar si metode pentru crearea si modificarea de noduri de arbore DOM. Exemple:
public String getNodeName(); // numele acestui nod
public String getNodeValue() throws DOMException; // valoarea acestui nod
public void setNodeValue(String nodeValue) throws DOMException;
public short getNodeType(); // tipul acestui nod
public NodeList getChildNodes(); // lista succesorilor acestui nod
public Node getFirstChild(); // primul succesor al acestui nod
public Node getNextSibling(); // urmatorul succesor al acestui nod
public NamedNodeMap getAttributes(); // atributele acestui nod
- Interfata NodeList contine metode pentru acces la lista de succesori ai unui nod:
public Node item(int index); // nodul cu numarul "index"
public int getLength(); // lungime lista de noduri
- Interfetele Document, Element, Attr, CharacterData, Text, Comment, extind direct sau indirect interfata Node cu metode specifice acestor tipuri de noduri.
Interfata NamedNodeMap corespunde unei liste de atribute (obiecte de tip Attr) si contine metode ca getLength() si item(i). Exemplu de extragere atribute:
Element elm=(Element) node; // Node node;
NamedNodeMap attrs = elm.getAttributes();
for (int i=0;i <attrs.getLength(); i++)
Attr a = (Attr) attrs.item(i);
Interfata Attr contine metode de acces la numele si valoarea unui atribut, precum si la elementul caruia apartine acel atribut:
public interface Attr extends Node
Din interfata Element vom mentiona cateva metode:
public String getAttribute(String name); // obtinerea valorii unui atribut cu nume dat
public void setAttribute(String name,String value) throws DOMException;
public NodeList getElementsByTagName(String name);
Ultima metoda este utila pentru extragerea selectiva de noduri dintr-un arbore DOM, dar exista in standardul DOM si alte mecanisme de filtrare a nodurilor din arbore.
Clasele care implementeaza interfetele DOM fac parte din parserul DOM, iar numele si implementarea lor nu sunt cunoscute utilizatorilor; ele constituie un bun exemplu de separare intre interfata si implementare si de programare la nivel de interfata. Clasa care implementeaza interfata Node contine si o metoda "toString", care produce un sir de forma nume[valoare], cu numele si valoarea nodului, indiferent de tipul nodului si daca exista sau nu atribute asociate unui element.
Afisarea/prelucrarea unui arbore DOM se face de obicei printr-o functie recursiva care prelucreaza nodul curent (primit ca argument), atributele sale si apoi se apeleaza pe ea insasi pentru fiecare succesor. Parcurgerea listei de succesori se poate face in doua moduri:
- Folosind metodele "getFirstChild" si "getNextSibling" ;
- Folosind metoda "getChildNodes" si metode ale interfetei NodeList.
Exemplu de afisare nume si valoare noduri DOM folosind prima varianta:
import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.File;
// afisare nume si valori noduri din arbore DOM (cu metoda Node.toString )
class DomEcho
}
public static void main (String arg[]) throws Exception
}
Exemplu pentru a doua solutie a functiei recursive:
public static void printNode(Node node)
La functiile anterioare se poate adauga un parametru suplimentar ce reprezinta nivelul sau indentarea necesara la fiecare nivel:
public static void printNode(Node node, String indent)
Metoda "Node.toString" predefinita poate fi inlocuita cu o metoda statica cu argument "Node" care sa tina seama de tipul nodului si sa adauge si atributele la sirul ce reprezinta continutul unui nod DOM (pentru noduri text nu se afiseaza numele, iar pentru nodurile element nu se afiseaza valoarea).
static String toString (Node node) else if (type==3) // daca nod text
s = node.getNodeValue().trim(); // valoare nod cu eliminare de spatii albe
return s;
}
In general, operatiile efectuate la fiecare nod depind de tipul nodului iar functia recursiva va contine o selectie dupa tipul nodului (un bloc switch). Exemplul urmator afiseaza frumos, cu indentare, rezultatul unui parser DOM, dar numai pentru noduri cu elemente si noduri text:
Functia anterioara poate fi modificata pentru serializarea unui arbore DOM, arbore care poate fi creat prin program (nu pe baza unui fisier XML) si apoi folosit pentru crearea unui fisier XML. Pentru serializare trebuie adaugate marcaje de sfarsit si paranteze unghiulare la marcaje.
Ca exemplu de creare a unui arbore DOM prin program (folosind metode ca "createElement", "createAttribute", createTextNode"), urmeaza fragmente dintr-un program care creeaza un obiect DOM folosind un parser SAX:
class SAXDOM extends DefaultHandler
// metode callback apelate de parserul SAX
public void startElement(String uri, String lName, String qName, Attributes atts)
throws SAXException
crt.appendChild(element);
crt = element;
}
public void endElement(String nsURI, String lName, String qName) throws SAXException
public void characters(char[] ch, int start, int length) throws SAXException
Utilizarea unui parser StAX
StAX reuneste doua interfete API, iar o aplicatie trebuie sa aleaga intre cele doua, numite API cursor si API iterator.
Modelul cursor are doua interfete Java principale: XMLStreamReader
si XMLStreamWriter
. Fragment din interfata pentru analiza unui document XML:
public interface XMLStreamReader
Fragment
din interfata XMLStreamWriter
:
public interface XMLStreamWriter
Metoda "next" are ca rezultat tipul atomului XML din dreptul cursorului si avansul cursorului pe urmatorul atom. Acest tip (un intreg) poate fi comparat cu una din constantele simbolice definite in interfata XMLEvent sau se pot folosi metode din interfata XMLStreamReader pentru determinarea tipului de atom XML. Exemplu:
XMLStreamReader xmlr;
.
while(xmlr.hasNext())
}
public static String toString (XMLStreamReader xr)
}
Modelul iterator lucreaza cu obiecte eveniment, obtinute prin metoda "nextEvent", si care contin toate informatiile despre urmatorul element de limbaj XML. Interfata XMLEvent contine constante si metode pentru analiza evenimentelor XML.
Interfetele pentru analiza si respectiv sinteza unui document XML din modelul iterator sunt XMLEventReader si XMLEventWriter:
public interface XMLEventReader extends Iterator
public interface XMLEventWriter
Exemplu de afisare in ecou a continutului unui fisier XML folosind clase si metode din modelul StAX iterator, inclusiv metoda "toString" a clasei care implementeaza interfata "XMLEvent":
import java.io.*;
import javax.xml.stream.*;
import javax.xml.stream.events.* ;
class EventEcho
}
}
Pentru afisare cu indentare trebuie determinat tipul evenimentului. Putem redefini metoda "toString" a obiectului eveniment XML pentru a adauga indentarea, dar nu cunoastem numele clasei care implementeaza interfata XMLEvent. Avem cateva posibilitati de a schimba sirul ce corespunde unui eveniment StAX:
- O metoda statica cu argument XMLEvent;
- O alta clasa care contine o variabila XMLEvent si o metoda toString (nestatica), definita de noi.
Exemplu pentru prima solutie:
class PPEvent
}
static String sp=''; // spatii ptr indentare
static String toString (XMLEvent ev)
}
Variabila "sp" trebuie sa fie statica pentru a-si pastra valoarea intre apeluri ale functiei "toString".
Crearea de obiecte XMLEvent pentru fiecare atom XML (inclusiv spatii albe) este un dezavantaj al modelului iterator fata de modelul cursor (ca memorie si ca timp).
Vizualizarea arborelui XML
Afisarea intr-un obiect JTree a rezultatului unui parser XML pune cateva probleme interesante de programare cu obiecte, fara a avea insa si o utilitate practica.
Pentru afisarea unui arbore DOM sub forma unui arbore JTree se poate crea un obiect JTree cu datele din arborele DOM, sau se poate stabili o corespondenta nod la nod intre cei doi arbori sau se poate folosi o clasa adaptor de la un tip de nod la un alt tip de nod (deoarece metodele necesare pentru pentru operatii cu noduri sunt prezente in ambele tipuri de noduri, dar sub alta forma).
Clasa adaptor primeste apeluri de metode din interfata TreeeNode si le transforma in apeluri de metode din interfata Node (DOM). Avem doua variante:
- Clasa adaptor implementeaza interfata TreeNode si primeste un obiect org.w3c.dom.Node;
- Clasa adaptor extinde clasa DefaultMutableTreeNode si primeste un obiect de tip Node.
Pentru economie de spatiu vom folosi a doua varianta si vom redefini numai metodele folosite la vizualizarea arborelui (alte metode care nu sunt folosite la vizualizare sunt folosite in aplicatii care prelucreaza arborele afisat si trebuie de asemenea redefinite) :
class NodeAdapter extends DefaultMutableTreeNode
public TreeNode getChildAt(int i)
public int getChildCount()
public String toString()
}
return s;
}
}
Utilizarea clasei adaptor se va face astfel:
public static void main(String argv[ ]) throws Exception
O alta solutie de afisare a unui arbore DOM intr-un obiect JTree se bazeaza pe definirea unei clase model de arbore, model care sa foloseasca ca noduri (inclusiv nodul radacina) chiar noduri DOM (radacina poate fi de orice subtip al clasei Object). In principiu se defineste o clasa care implementeaza metodele interfetei TreeModel prin apeluri de metode din interfata Node (DOM), dar din nou apare problema redefinirii metodei "toString" dintr-o clasa cu nume necunoscut (clasa pentru nod DOM) pentru a tine seama de tipul nodului (ca si in cazul clasei pentru XMLEvent).
Putem sa definim o clasa pentru o varianta de nod DOM cu metoda "toString" redefinita si cu cateva metode noi, utile in clasa model de arbore:
class DomNode
public String toString()
if (domNode.getNodeValue() != null)
return s;
}
// Metode noi pentru indici si numar fii
public int index( DomNode child)
return -1;
}
public DomNode child(int searchIndex)
public int childCount()
}
Clasa model de arbore cu noduri DOM arata astfel:
class DomTreeModel implements TreeModel
// Metode din interfata TreeModel
public Object getRoot()
public boolean isLeaf(Object aNode)
public int getChildCount(Object parent)
public Object getChild(Object parent, int index)
public int getIndexOfChild(Object parent, Object child)
public void valueForPathChanged(TreePath path, Object newValue)
private Vector listenerList = new Vector();
public void addTreeModelListener(TreeModelListener listener)
public void removeTreeModelListener(TreeModelListener listener)
}
Urmeaza clasa responsabila cu afisarea arborelui:
class domView extends JFrame
public static void main(String argv[]) throws Exception
}
Solutiile anterioare folosesc eficient memoria (nu dubleaza arborele DOM intr-un arbore JTree), dar nu pot elimina nodurile text cu spatii albe, pentru ca se preiau toate nodurile DOM in arborele afisat cu JTree (nu se pot exclude noduri DOM decat cu anumite artificii).
O solutie mai simpla construieste un arbore JTree avand in noduri referinte la noduri din arborele DOM; se pot elimina noduri text care contin numai spatii albe, dar in memorie se vor afla doi arbori:
class domJTree1
// adaugare nod fiu la nod parinte din arbore DOM in arbore JTree
private static void add ( TNode child, TNode parent)
}
O aplicatie cu fisiere XML
Programul Ant (Apache) realizeaza o secventa de actiuni descrisa intr-un fisier XML, cu numele implicit "build.xml" sau cu un alt nume dat ca argument in comanda "ant" (unde mai pot apare si o serie de optiuni). O actiune ("target") consta din mai multe operatii, are un nume si o actiune anterioara, de care depinde.
O operatie ("task") consta de obicei in executarea unui program sau unei comenzi de sistem. Exista mai multe operatii cu nume predefinit dar si operatii generice, cum ar fi executia oricarei comenzi de sistem (nume de target "exec"). Exemple de operatii predefinite : exec, mkdir, copy, delete, javac, java, etc.
Urmeaza un exemplu simplu de fisier "build.xml" cu 3 actiuni: stergerea unor fisiere ("clean"), crearea unui nou director ("mkdir"), si copierea unui fisier in noul director ("copy"):
<project name='MyProject' default='copy' >
<target name='clean' description='delete files ' >
<echo
message='
<delete dir='dist' />
</target>
<target name='mkdir' depends='clean'>
<mkdir dir='dist'/>
</target>
<target name='copy' depends='mkdir' description='copy files ' >
<copy file='build.xml' tofile='dist/build.xml' />
</target>
</project>
Un element "target" descrie o actiune, iar fiecare element continut de "target" reprezinta un task (o operatie). Ordinea de executie va fi: "copy", "mkdir", "clean" deoarece actiunea implicita din acest proiect este "copy", iar "copy" depinde de "mkdir", care depinde de "clean".
De mentionat ca actiunile pot fi descrise in orice ordine, chiar daca actiunea de care depinde actiunea curenta nu a fost deja descrisa. Exemplu de fisier "build.xml":
<project name='MyProject' default='cinci' >
<target name='trei' depends='doi' > <echo message= '3' /> </target>
<target name='cinci' depends='patru' > <echo message= '5' /> </target>
<target name='unu' > <echo message= '1' /> </target>
<target name='doi' depends='unu' > <echo message= '2' /> </target>
<target name='patru' depends='trei' > <echo message= '4' /> </target>
</project>
Rezultatul executiei fisierului anterior de catre "ant" va fi:
Buildfile: build.xml
unu:
[echo] 1
doi:
[echo] 2
trei:
[echo] 3
patru:
[echo] 4
cinci:
[echo] 5
BUILD SUCCESSFUL
Total time: 0 seconds
Vom schita un mic program "ant", mult simplificat in raport cu programul originar, dar care reda esenta acestuia. Simplificarea rezida in numele de task-uri si de atribute ce pot apare in fisierul "build.xml", dar se pastreaza functionalitatea programului "ant".
Si in aceasta aplicatie ierarhia de elemente XML este importanta: astfel un task poate avea orice nume si este executat numai daca apare in cadrul unui target. Anumite elemente task ("exec", de exemplu) pot contine alte elemente (argumente pentru executia comenzii). Vom prefera de aceea un parser DOM care retine si relatile de subordonare dintre elemente, spre deosebire de un parser secvential (SAX).
Programul are trei parti distincte, dar diferite ca dimensiune: crearea unei liste de actiuni (targets), in ordinea aparitiei lor in proiect, stabilirea ordinii de executie pentru aceste actiuni, executia fiecarui task dintr-o actiune, functie de tipul operatiei.
Toate elementele de tip target vor fi introduse intr-o lista (un vector) pe masura ce sunt intalnite in fisierul "build.xml". Pentru stabilirea ordinii de executie vom incepe cu targetul implicit (atributul "default" din elementul "project") si vom parcurge lantul de dependente, punand elementele intr-o stiva (lantul de executie este parcurs in ordine inversa folosing atributul "depends" al fiecarui target). Executia actiunilor din proiect se va face in ordinea extragerii din stiva.
Programul incepe prin obtinerea obiectului parser si executia acestuia pentru crearea obiectului de tip Document (arborele DOM):
class AntDOM
}
Metoda "handleProject" creeaza lista de actiuni si retine actiunea de start:
class DOMHandler
execprj(); // executie actiuni din proiect
}
Metoda "execprj" stabileste ordinea de executie pentru actiuni folosind o stiva si lanseaza secventa de operatii din fiecare actiune:
private void execprj ()
stack.push(tt); // pune target pe stiva
tn= tt.getAttribute('depends'); // urmatorul target in lantul dependentelor
}
// executie targets in ordinea din stiva
while ( ! stack.empty())
}
}
Metoda "exectask" depinde de numele si de atributele elementului task si de aceea ne vom limita la cateva operatii simple:
private void exectask (Element task) // lansare comanda
catch(Exception e)
}
System.out.println(); // dupa orice task
}
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 2154
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved