Συντακτική ανάλυση εγγράφων XML µε Xerces Σταύρος Πολυβίου Simple API for XML (SAX) ιεπαφή η οποία χρησιµοποιείται ευρέως και έχει υλοποιηθεί για διάφορους αναλυτές σύνταξης XML Η πλέον καθιερωµένη διεπαφή για ανάλυση σύνταξης XML εγγράφων βάσει συµβάντων (event-based XML parsing) Το SAX είναι µία διεπιφάνεια, ένα πρωτόκολλο και όχι ένας αναλυτής σύνταξης Το SAX2 είναι η τελευταία έκδοση της διεπιφάνειας σε Java και µε υποστήριξη των XML namespaces 1
Τί είναι µία διεπιφάνεια βάσει συµβάντων; Τέτοιου είδους διεπιφάνειες αναφέρουν συµβάντα που αφορούν στη συντακτική ανάλυση έγγράφων στην εφαρµογή µέσω αναστροφών κλήσης (callbacks). Αρχή εγγράφου (Start Document) Αρχή στοιχείου (Start Element) Τέλος στοιχείου (End Element) κ.ο.κ. Η εφαρµογή υλοποιεί χειριστές (handlers) για να αντιµετωπίσει τα συµβάντα Τέτοιου είδους διεπιφάνειες προσφέρουν ένα απλό τρόπο πρόσβασης σε ένα XML έγγραφο σε χαµηλό επίπεδο Επιτρέπουν τη συντακτική ανάλυση εγγράφων που δε µπορούν να χωρέσουν στη µνήµη του συστήµατος Οποιεσδήποτε δοµές δεδοµένων για την αποθήκευση πληροφοριών που εξάγονται από το έγγραφο δηµιουργούνται από τους χειριστές των συµβάντων Τρόπος λειτουργίας του SAX Έστω το ακόλουθο XML έγγραφο: <?xml version="1.0"?> <Name> <Last_Name>Polyviou</Last_Name> <First_Name>Stavros</First_Name> </Name> Συµβάντα: start document start element: Name start element: Last_Name characters: Polyviou end element: Last_Name start element: First_Name characters: Stavros end element: First_Name end element: Name end document 2
Παράδειγµα Εκτύπωση µίας λίστας µε όλα τα στοιχεία του ακόλουθου XML εγγράφου: <?xml version="1.0"?> <course> <name id= EPL425">Internet Technologies</name> <teacher id= sp"> <name>stavros Polyviou</name> </teacher> <student id= aa"> <name>andreas Andreou</name> <hw1>30</hw1> <hw2>70</hw2> <project>80</project> <final>85</final> </student> Παράδειγµα (2) <student id= aa2"> <name>andri Andreou</name> <hw1>80</hw1> <hw2>90</hw2> <project>100</project> <final>40</final> </student> <student id= aa3"> <name>antonis Antoniou</name> <hw1>60</hw1> <hw2>95</hw2> <project>50</project> <final>90</final> </student> </course> 3
Ανάλυση σύνταξης µε τον Xerces import org.xml.sax.*; import org.xml.sax.helpers.defaulthandler; import org.apache.xerces.parsers.saxparser; public class SaxNames extends DefaultHandler public static void main(string[] args) SaxNames SAXHandler = new SaxNames(); SAXParser parser = new SAXParser();... ΗκλάσηDefaultHandler Παρέχει προτερόθετες υλοποιήσεις όλων των µεθόδων αναστοφής κλήσης (callback methods) Υποχρεωτικές µέθοδοι void characters(char[] ch, int start, int length) void enddocument() void endelement(string uri, String localname, String rawname) void startdocument() void startelement(string uri, String localname, String rawname, Attributes attributes) 4
ΗκλάσηSAXParser Είναι υποκλάση της κλάσης XMLParser java.lang.object org.apache.xerces.framework.xmlparser org.apache.xerces.parsers.saxparser Το SAXHandler αντικείµενο θα πρέπει να καταχωρηθεί στο SAXParser αντικείµενο Παράδειγµα Xerces import org.xml.sax.*; import org.xml.sax.helpers.defaulthandler; import org.apache.xerces.parsers.saxparser; public class SaxNames extends DefaultHandler public void startelement(string uri, String localname, String rawname, Attributes attributes) System.out.println("Element : " + localname); 5
Παράδειγµα Xerces (2) public static void main(string[] args) try SaxNames SAXHandler = new SaxNames(); SAXParser parser = new SAXParser(); parser.setcontenthandler(saxhandler); parser.seterrorhandler(saxhandler); parser.parse(args[0]); catch(exception e) e.printstacktrace(system.err); Αποτέλεσµα εκτέλεσης Element : course Element : name Element : teacher Element : student Element : name Element : hw1 Element : hw2 Element : project Element : final Element : student Element : name Element : hw1 Element : hw2 Element : project Element : final Element : student Element : name Element : hw1 Element : hw2 Element : project Element : final 6
Παράδειγµα 2 Υπολογισµός µέσου όρου βαθµολογίας για τον εκάστοτε φοιτητή και για ολόκληρο το µάθηµα. Ορισµός κλάσεων import org.xml.sax.*; import org.xml.sax.helpers.defaulthandler; import org.apache.xerces.parsers.saxparser; class SaxParserGrades extends DefaultHandler... 7
Ορισµός κλάσεων (2) public class SaxGrades public static void main(string[] args) try SaxParserGrades SAXHandler = new SaxParserGrades(); SAXParser parser = new SAXParser(); parser.setcontenthandler(saxhandler); parser.seterrorhandler(saxhandler); parser.parse(args[0]); catch(exception e) e.printstacktrace(system.err); Ορισµός startelement και endelement (κλάση SaxParserGrades) static float grades[][] = new float[100][5]; int gi = -1; intnstudent= 0; public void startelement(string uri, String localname, String rawname, Attributes attributes) if (localname.equals("hw1")) gi = 0; else if (localname.equals("hw2")) gi = 1; else if (localname.equals("project")) gi = 2; else if (localname.equals("final")) gi = 3; else if (localname.equals("student")) nstudent++; public void endelement(string uri, String localname, String rawname) gi = -1; 8
Ορισµός characters public void characters(char characters[], int start, int length) String chdata = (new String(characters, start, length)).trim(); if (chdata.indexof("\n") < 0 && chdata.length() > 0) if (gi >= 0) grades[nstudent-1][gi] = Integer.parseInt(chData); Ορισµός enddocument public void enddocument() float Ave = 0; int i = 0, j = 0; System.out.println("Grades"); for(i = 0; i < nstudent ; i++) float total = 0; for(j = 0; j < 4; j++) total += grades[i][j]; grades[i][4] = total/4; Ave += grades[i][4]; System.out.println("Student " + i + "=" + grades[i][4]); Ave /= nstudent; System.out.println("Class Average = " + Ave); 9
Αποτέλεσµα εκτέλεσης Grades Student 0= 66.25 Student 1= 77.5 Student 2= 73.75 Class Average = 72.5 Χρήση χαρακτηριστικών (attributes) ιεπιφάνεια Attributes int getindex(string rawname) Επιστρέφει το δείκτη ενός χαρακτηριστικού βάσει του ονόµατός του String getrawname(int index) Επιστρέφει το όνοµα ενός χαρακτηριστικού βάσει του δείκτη του String getvalue(int index) Επιστρέφει την τιµή ενός χαρακτηριστικού βάσει του δείκτη του String getvalue(string rawname) Επιστρέφει την τιµή ενός χαρακτηριστικού βάσει του ονόµατός του 10
Παράδειγµα 3 Υπολογισµόςτωνεπιφανειώντωνπιοκάτωσχηµάτων: <?xml version="1.0"?> <figures> <circle x="20" y="10" r="20"/> <rectangle x="-3" y="4" w="5" h="36"/> <ellipse x="-5" y="6" w="30" h="50"/> <rectangle x="7" y="23" w="58" h="45"/> <circle x="-2" y="5" r="35"/> <ellipse x="-10" y="-8" w="45" h="30"/> </figures> Παράδειγµα 3 µε Xerces import org.xml.sax.*; import org.xml.sax.helpers.defaulthandler; import org.apache.xerces.parsers.saxparser; public class SaxFigures extends DefaultHandler public void startelement(string uri, String localname, String rawname, Attributes attributes) if(localname.equals("circle")) String sr = attributes.getvalue("r"); float radius = Float.valueOf(sr).floatValue(); float area = (float)math.pi*radius*radius; System.out.println("Circle : Radius = " + radius + " Area = " + area); 11
Παράδειγµα 3 µε Xerces (2) else if(localname.equals("ellipse")) String sw = attributes.getvalue("w"); String sh = attributes.getvalue("h"); float width = Float.valueOf(sw).floatValue(); float height = Float.valueOf(sh).floatValue(); float area = (float)math.pi*(width/2)*(height/2); System.out.println("Ellipse : Width = " + width + " Height = " + height + " Area = " + area); Παράδειγµα 3 µε Xerces (3) else if(localname.equals("rectangle")) String sh = attributes.getvalue("h"); String sw = attributes.getvalue("w"); float width = Float.valueOf(sw).floatValue(); float height = Float.valueOf(sh).floatValue(); float area = width * height; System.out.println("Rectangle : Width = " + width + " Height = " + height + " Area = " + area); 12
Παράδειγµα 3 µε Xerces (4) public static void main(string[] args) try SaxFigures SAXHandler = new SaxFigures(); SAXParser parser = new SAXParser(); parser.setcontenthandler(saxhandler); parser.seterrorhandler(saxhandler); parser.parse(args[0]); catch(exception e) e.printstacktrace(system.err); Αποτέλεσµα εκτέλεσης Circle : Radius = 20.0 Area = 1256.6371 Rectangle : Width = 5.0 Height = 36.0 Area = 180.0 Ellipse : Width = 30.0 Height = 50.0 Area = 1178.0973 Rectangle : Width = 58.0 Height = 45.0 Area = 2610.0 Circle : Radius = 35.0 Area = 3848.4512 Ellipse : Width = 45.0 Height = 30.0 Area = 1060.2876 13
To Document Object Model Τα XML έγγραφα αντιµετωπίζονται ως δέντρα αποτελούµενα από κόµβους Ιστοσελίδα: http://www.w3.org/dom/ Οι κλάσεις των W3C XML DOM αντικειµένων Element - Στοιχείο Attribute - Χαρακτηριστικό Text Περιεχόµενο/τιµή στοιχείου/χαρακτηριστικού CDATAsection τµήµα CDATA EntityReference Αναφορά σε οντότητα Entity - Οντότητα ProcessingInstruction Εντολή επεξεργασίας Comment Περιεχόµενο σχολίου Document - Έγγραφο DocumentType - Το <!DOCTYPE> στοιχείο DocumentFragment Αναφορά σε τµήµα εγγράφου Notation Σηµειογραφία (πολύ σπάνιο) 14
Κλάσεις που σχετίζονται µε κόµβους Node κόµβος του XML δέντρου NodeList λίστα από κόµβους NamedNodeMap Επιτρέπει πρόσβαση σε χαρακτηριστικά βάσει του ονόµατός τους Η κλάση DOMParser Υποκλάση της κλάσης XMLParser java.lang.object org.apache.xerces.framework.xmlparser org.apache.xerces.parsers.domparser Η µέθοδος parse() αναλυέι συντακτικά την είσοδο Η µέθοδος getdocument() επιστρέφει το ίδιο το έγγραφο 15
Η διεπιφάνεια Document Attr createattribute(string name) ηµιουργεί ένα χαρακτηριστικό µε όνοµα name Element createelement(string tagname) ηµιουργεί ένα στοιχείου του τύπου tagname Text createtextnode(string data) ηµιουργεί ένα κόµβο κειµένου Element getdocumentelement() Επιστρέφει το στοιχείο ρίζατ του εγγράφου Element getelementbyid(string elementid) Επιστρέφει ένα στοιχείο βάσει της ταυτότητάς του NodeList getelementsbytagname(string tagname) Επιστρέφει µία λίστα µε όλα τα στοιχεία του τύπου tagname Η διεπιφάνεια NodeList int getlength() Επιστρέφει τον αριθµό των κόµβων στη λίστα Node item(int index) Επιστρέφει τον κόµβο που βρίσκεται στη θέση index της λίστας 16
ΗδιεπιφάνειαNode NamedNodeMap getattributes() Επιστρέφει µία λίστα µε τα χαρακτηριστικά του κόµβου NodeList getchildnodes() Επιστρέφει όλα τα παιδιά του κόµβου String getlocalname() Επιστρέφει το τοπικό όνοµα του κόµβου String getnodename() Επιστρέφει το όνοµα του κόµβου String getnodevalue() Επιστρέφει την τιµή του κόµβου Node getparentnode() Επιστρέφει τον γονέα του κόµβου short getnodetype() Επιστρέφει ένα κωδικό που υποδηλώνει τον τύπο του κόµβου Τύποι κόµβων static short ATTRIBUTE_NODE static short CDATA_SECTION_NODE static short COMMENT_NODE static short DOCUMENT_FRAGMENT_NODE static short DOCUMENT_NODE static short DOCUMENT_TYPE_NODE static short ELEMENT_NODE static short ENTITY_NODE static short ENTITY_REFERENCE_NODE static short NOTATION_NODE static short PROCESSING_INSTRUCTION_NODE static short TEXT_NODE 17
Παράδειγµα: εκτύπωση λίστας στοιχείων (µε αναδροµή) import org.w3c.dom.*; import org.apache.xerces.parsers.domparser; class DisplayElements public static void displaydocument(string uri) try DOMParser parser = new DOMParser(); parser.parse(uri); Document doc = parser.getdocument(); display_names(doc); catch (Exception e) e.printstacktrace(system.err); Παράδειγµα: εκτύπωση λίστας στοιχείων (µε αναδροµή) (2) public static void display_names(node node) if (node == null) return; int type = node.getnodetype(); switch (type) case Node.DOCUMENT_NODE: display_names(((document)node).getdocumentelement()); break; 18
Παράδειγµα: εκτύπωση λίστας στοιχείων (µε αναδροµή) (3) case Node.ELEMENT_NODE: System.out.println("Element : " + node.getnodename()); NodeList childnodes = node.getchildnodes(); if(childnodes!= null) int length = childnodes.getlength(); for (int loopindex = 0; loopindex < length ; loopindex++) display_names(childnodes.item(loopindex)); break; Παράδειγµα: εκτύπωση λίστας στοιχείων (µε αναδροµή) (4) public class DOMNameElements public static void main(string[] args) DisplayElements.displayDocument(args[0]); 19
Αποτέλεσµα εκτέλεσης Element : course Element : name Element : teacher Element : student Element : name Element : hw1 Element : hw2 Element : project Element : final Element : student Element : name Element : hw1 Element : hw2 Element : project Element : final Element : student Element : name Element : hw1 Element : hw2 Element : project Element : final 20