Προγραμματισμός

Αντιστοίχιση XML σε Java, Μέρος 1

Το XML είναι ζεστό. Επειδή το XML είναι μια μορφή αυτο-περιγραφόμενων δεδομένων, μπορεί να χρησιμοποιηθεί για την κωδικοποίηση μοντέλων εμπλουτισμένων δεδομένων. Είναι εύκολο να δείτε τη χρησιμότητα της XML ως μέσο ανταλλαγής δεδομένων μεταξύ πολύ ανόμοιων συστημάτων. Τα δεδομένα μπορούν εύκολα να εκτεθούν ή να δημοσιευτούν ως XML από όλα τα είδη συστημάτων: προγράμματα COBOL παλαιού τύπου, βάσεις δεδομένων, προγράμματα C ++ και ούτω καθεξής.

ΠΛΑΙΣΙΟ ΚΕΙΜΕΝΟΥ:

TEXTBOX_HEAD: Χαρτογράφηση XML σε Java: Διαβάστε ολόκληρη τη σειρά!

  • Μέρος 1 - Χρησιμοποιήστε το API SAX για να χαρτογραφήσετε έγγραφα XML σε αντικείμενα Java
  • Μέρος 2 - Δημιουργήστε μια βιβλιοθήκη τάξης που χρησιμοποιεί το API SAX για τη χαρτογράφηση εγγράφων XML σε αντικείμενα Java

: END_TEXTBOX

Ωστόσο, η χρήση XML για την κατασκευή συστημάτων θέτει δύο προκλήσεις. Πρώτον, ενώ η δημιουργία XML είναι μια απλή διαδικασία, η αντίστροφη λειτουργία, χρησιμοποιώντας δεδομένα XML από ένα πρόγραμμα, δεν είναι. Δεύτερον, οι τρέχουσες τεχνολογίες XML είναι εύκολο να εφαρμοστούν εσφαλμένα, γεγονός που μπορεί να αφήσει έναν προγραμματιστή με ένα αργό, πεινασμένο στη μνήμη σύστημα. Πράγματι, οι απαιτήσεις μεγάλης μνήμης και οι αργές ταχύτητες μπορούν να αποδειχθούν προβληματικές για συστήματα που χρησιμοποιούν το XML ως την κύρια μορφή ανταλλαγής δεδομένων.

Ορισμένα τυπικά εργαλεία που διατίθενται προς το παρόν για εργασία με XML είναι καλύτερα από άλλα. Το SAX API έχει συγκεκριμένα ορισμένα σημαντικά χαρακτηριστικά χρόνου εκτέλεσης για κώδικα ευαίσθητο στην απόδοση. Σε αυτό το άρθρο, θα αναπτύξουμε ορισμένα μοτίβα για την εφαρμογή του API SAX. Θα μπορείτε να δημιουργήσετε γρήγορο κώδικα χαρτογράφησης XML σε Java με ελάχιστο αποτύπωμα μνήμης, ακόμη και για αρκετά περίπλοκες δομές XML (με εξαίρεση τις αναδρομικές δομές).

Στο Μέρος 2 αυτής της σειράς, θα καλύψουμε την εφαρμογή του API SAX σε αναδρομικές δομές XML στις οποίες ορισμένα από τα στοιχεία XML αντιπροσωπεύουν λίστες λιστών. Θα αναπτύξουμε επίσης μια βιβλιοθήκη τάξεων που διαχειρίζεται τις πτυχές πλοήγησης του SAX API. Αυτή η βιβλιοθήκη απλοποιεί τη σύνταξη κώδικα αντιστοίχισης XML με βάση το SAX.

Ο κωδικός χαρτογράφησης είναι παρόμοιος με τη σύνταξη κώδικα

Η σύνταξη προγραμμάτων που χρησιμοποιούν δεδομένα XML είναι σαν να γράφετε έναν μεταγλωττιστή. Δηλαδή, οι περισσότεροι μεταγλωττιστές μετατρέπουν τον πηγαίο κώδικα σε ένα τρέξιμο πρόγραμμα σε τρία βήματα. Πρώτον, α λεξέρ η ενότητα ομαδοποιεί χαρακτήρες σε λέξεις ή μάρκες που αναγνωρίζει ο μεταγλωττιστής - μια διαδικασία γνωστή ως tokenizing. Μια δεύτερη ενότητα, που ονομάζεται αναλυτής, αναλύει ομάδες διακριτικών για να αναγνωρίσει νομικές δομές γλώσσας. Τελευταία, μια τρίτη ενότητα, η γεννήτρια κώδικα, παίρνει ένα σύνολο δομών νομικής γλώσσας και δημιουργεί εκτελέσιμο κώδικα. Μερικές φορές, η ανάλυση και η δημιουργία κώδικα συνδυάζονται.

Για να χρησιμοποιήσουμε δεδομένα XML σε ένα πρόγραμμα Java, πρέπει να υποβληθούμε σε μια παρόμοια διαδικασία. Αρχικά, αναλύουμε κάθε χαρακτήρα στο κείμενο XML προκειμένου να αναγνωρίσουμε νόμιμα διακριτικά XML, όπως ετικέτες έναρξης, χαρακτηριστικά, τελικές ετικέτες και ενότητες CDATA.

Δεύτερον, επαληθεύουμε ότι τα διακριτικά αποτελούν νόμιμες κατασκευές XML. Εάν ένα έγγραφο XML αποτελείται εξ ολοκλήρου από νομικές κατασκευές σύμφωνα με την προδιαγραφή XML 1.0, είναι καλοδιαμορφωμένο. Στο πιο βασικό επίπεδο, πρέπει να διασφαλίσουμε ότι, για παράδειγμα, όλες οι ετικέτες έχουν αντίστοιχες ετικέτες ανοίγματος και κλεισίματος και ότι τα χαρακτηριστικά είναι σωστά δομημένα στην ετικέτα ανοίγματος.

Επίσης, εάν είναι διαθέσιμο ένα DTD, έχουμε την επιλογή να βεβαιωθούμε ότι οι κατασκευές XML που βρέθηκαν κατά την ανάλυση είναι νόμιμες από την άποψη του DTD, καθώς και ότι είναι καλά διαμορφωμένες XML.

Τέλος, χρησιμοποιούμε τα δεδομένα που περιέχονται στο έγγραφο XML για να πετύχουμε κάτι χρήσιμο - ονομάζω αυτήν τη χαρτογράφηση XML σε Java.

Αναλυτές XML

Ευτυχώς, υπάρχουν εκτός λειτουργίας - εξαρτήματα ανάλυσης XML - που εκτελούν ορισμένες από αυτές τις εργασίες που σχετίζονται με τον μεταγλωττιστή για εμάς. Οι αναλυτές XML χειρίζονται όλες τις λεξικές αναλύσεις και εργασίες ανάλυσης για εμάς. Πολλά διαθέσιμα προγράμματα ανάλυσης XML που βασίζονται σε Java υποστηρίζουν δύο δημοφιλή πρότυπα ανάλυσης: τα API SAX και DOM.

Η διαθεσιμότητα ενός ανεξάρτητου προγράμματος ανάλυσης XML μπορεί να σας κάνει να φαίνεται ότι το δύσκολο μέρος της χρήσης XML στην Java έχει γίνει για εσάς. Στην πραγματικότητα, η εφαρμογή ενός ανεξάρτητου προγράμματος ανάλυσης XML είναι μια εμπλεκόμενη εργασία.

API SAX και DOM

Το SAX API βασίζεται σε συμβάντα. Οι αναλυτές XML που εφαρμόζουν το SAX API δημιουργούν συμβάντα που αντιστοιχούν σε διαφορετικές δυνατότητες που βρίσκονται στο έγγραφο ανάλυσης XML. Απαντώντας σε αυτήν τη ροή συμβάντων SAX σε κώδικα Java, μπορείτε να γράψετε προγράμματα που βασίζονται σε δεδομένα που βασίζονται σε XML.

Το API DOM είναι ένα API βάσει αντικειμένου. Οι αναλυτές XML που εφαρμόζουν το DOM δημιουργούν ένα γενικό μοντέλο αντικειμένου στη μνήμη που αντιπροσωπεύει τα περιεχόμενα του εγγράφου XML. Μόλις το πρόγραμμα ανάλυσης XML ολοκληρώσει την ανάλυση, η μνήμη περιέχει ένα δέντρο αντικειμένων DOM που προσφέρει πληροφορίες σχετικά με τη δομή και το περιεχόμενο του εγγράφου XML.

Η έννοια DOM αναπτύχθηκε από τον κόσμο του προγράμματος περιήγησης HTML, όπου ένα κοινό μοντέλο αντικειμένου εγγράφου αντιπροσωπεύει το έγγραφο HTML που έχει φορτωθεί στο πρόγραμμα περιήγησης. Αυτό το HTML DOM γίνεται στη συνέχεια διαθέσιμο για scripting γλώσσες όπως το JavaScript. Το HTML DOM ήταν πολύ επιτυχημένο σε αυτήν την εφαρμογή.

Κίνδυνοι του DOM

Με την πρώτη ματιά, το DOM API φαίνεται να είναι πιο πλούσιο σε χαρακτηριστικά και, συνεπώς, καλύτερα από το SAX API. Ωστόσο, το DOM αντιμετωπίζει σοβαρά προβλήματα απόδοσης που μπορούν να βλάψουν εφαρμογές ευαίσθητες στην απόδοση.

Η τρέχουσα ομάδα ανάλυσης XML που υποστηρίζει το DOM εφαρμόζει το μοντέλο αντικειμένου στη μνήμη δημιουργώντας πολλά μικροσκοπικά αντικείμενα που αντιπροσωπεύουν κόμβους DOM που περιέχουν κείμενο ή άλλους κόμβους DOM. Αυτό ακούγεται αρκετά φυσικό, αλλά έχει αρνητικές επιπτώσεις στην απόδοση. Μία από τις πιο ακριβές λειτουργίες της Java είναι η νέος χειριστής. Αντίστοιχα, για κάθε νέος τελεστής που εκτελείται στην Java, ο συλλέκτης απορριμμάτων JVM πρέπει τελικά να αφαιρέσει το αντικείμενο από τη μνήμη όταν δεν παραμένουν αναφορές στο αντικείμενο. Το API DOM τείνει να ρίχνει πραγματικά το σύστημα μνήμης JVM με τα πολλά μικρά του αντικείμενα, τα οποία συνήθως πετιούνται αμέσως μετά την ανάλυση.

Ένα άλλο ζήτημα DOM είναι το γεγονός ότι φορτώνει ολόκληρο το έγγραφο XML στη μνήμη. Για μεγάλα έγγραφα, αυτό γίνεται πρόβλημα. Και πάλι, δεδομένου ότι το DOM υλοποιείται ως τόσα μικροσκοπικά αντικείμενα, το αποτύπωμα μνήμης είναι ακόμη μεγαλύτερο από το ίδιο το έγγραφο XML, επειδή η JVM αποθηκεύει μερικά επιπλέον byte πληροφοριών σχετικά με όλα αυτά τα αντικείμενα, καθώς και τα περιεχόμενα του εγγράφου XML.

Είναι επίσης ανησυχητικό ότι πολλά προγράμματα Java δεν χρησιμοποιούν στην πραγματικότητα τη γενική δομή αντικειμένων του DOM. Αντ 'αυτού, μόλις η δομή DOM φορτωθεί στη μνήμη, αντιγράφουν τα δεδομένα σε ένα μοντέλο αντικειμένου ειδικά για έναν συγκεκριμένο προβληματικό τομέα - μια λεπτή αλλά σπατάλη διαδικασία.

Ένα άλλο λεπτό ζήτημα για το DOM API είναι ότι ο κωδικός που γράφεται για αυτό πρέπει να σαρώσει το έγγραφο XML δύο φορές. Το πρώτο πέρασμα δημιουργεί τη δομή DOM στη μνήμη, το δεύτερο εντοπίζει όλα τα δεδομένα XML που ενδιαφέρει το πρόγραμμα. Ορισμένα στυλ κωδικοποίησης ενδέχεται να διασχίζουν τη δομή DOM αρκετές επιπλέον φορές ενώ εντοπίζουν διαφορετικά κομμάτια δεδομένων XML. Αντίθετα, το στυλ κωδικοποίησης του SAX ενθαρρύνει τον εντοπισμό και τη συλλογή δεδομένων XML σε ένα πάσο.

Μερικά από αυτά τα ζητήματα θα μπορούσαν να αντιμετωπιστούν με έναν καλύτερο υποκείμενο σχεδιασμό δομής δεδομένων για την εσωτερική εκπροσώπηση του μοντέλου αντικειμένου DOM. Ζητήματα όπως η ενθάρρυνση πολλαπλών περάσεων επεξεργασίας και η μετάφραση μεταξύ γενικών και συγκεκριμένων μοντέλων αντικειμένων δεν μπορούν να αντιμετωπιστούν εντός του προγράμματος ανάλυσης XML.

SAX για επιβίωση

Σε σύγκριση με το DOM API, το SAX API είναι μια ελκυστική προσέγγιση. Το SAX δεν διαθέτει μοντέλο γενικού αντικειμένου, επομένως δεν έχει προβλήματα μνήμης ή απόδοσης που σχετίζονται με την κατάχρηση του νέος χειριστής. Και με το SAX, δεν υπάρχει γενικό μοντέλο αντικειμένου που να αγνοείται εάν σκοπεύετε να χρησιμοποιήσετε ένα συγκεκριμένο μοντέλο αντικειμένου προβλήματος τομέα. Επιπλέον, δεδομένου ότι το SAX επεξεργάζεται το έγγραφο XML σε ένα μόνο πέρασμα, απαιτεί πολύ λιγότερο χρόνο επεξεργασίας.

Το SAX έχει μερικά μειονεκτήματα, αλλά σχετίζονται κυρίως με τον προγραμματιστή και όχι με την απόδοση χρόνου εκτέλεσης του API. Ας δούμε μερικά.

Το πρώτο μειονέκτημα είναι εννοιολογικό. Οι προγραμματιστές είναι συνηθισμένοι στην πλοήγηση για τη λήψη δεδομένων. για να βρείτε ένα αρχείο σε ένα διακομιστή αρχείων, πλοηγηθείτε αλλάζοντας καταλόγους. Ομοίως, για τη λήψη δεδομένων από μια βάση δεδομένων, γράφετε ένα ερώτημα SQL για τα δεδομένα που χρειάζεστε. Με το SAX, αυτό το μοντέλο είναι ανεστραμμένο. Δηλαδή, ρυθμίζετε κώδικα που ακούει τη λίστα κάθε διαθέσιμου κομματιού διαθέσιμων δεδομένων XML. Αυτός ο κωδικός ενεργοποιείται μόνο όταν αναφέρονται ενδιαφέροντα δεδομένα XML. Αρχικά, το SAX API φαίνεται περίεργο, αλλά μετά από λίγο, η σκέψη με αυτόν τον ανεστραμμένο τρόπο γίνεται δεύτερη φύση.

Το δεύτερο μειονέκτημα είναι πιο επικίνδυνο. Με τον κωδικό SAX, η αφελής προσέγγιση «ας το χακάρουμε» θα αντιδράσει αρκετά γρήγορα, επειδή ο αναλυτής SAX πλοηγεί εξαντλητικά τη δομή XML ενώ ταυτόχρονα παρέχει τα δεδομένα που είναι αποθηκευμένα στο έγγραφο XML. Οι περισσότεροι άνθρωποι εστιάζουν στην πτυχή χαρτογράφησης δεδομένων και παραμελούν την πτυχή της πλοήγησης. Εάν δεν αντιμετωπίζετε άμεσα την πτυχή πλοήγησης της ανάλυσης SAX, ο κώδικας που παρακολουθεί τη θέση εντός της δομής XML κατά τη διάρκεια της ανάλυσης SAX θα εξαπλωθεί και θα έχει πολλές λεπτές αλληλεπιδράσεις. Αυτό το πρόβλημα είναι παρόμοιο με εκείνο που σχετίζεται με την υπερβολική εξάρτηση από καθολικές μεταβλητές. Αλλά αν μάθετε να κατασκευάζετε σωστά τον κώδικα SAX για να τον αποτρέψετε να γίνει δυσκίνητος, είναι πιο απλό από τη χρήση του API DOM.

Βασικό SAX

Αυτήν τη στιγμή υπάρχουν δύο δημοσιευμένες εκδόσεις του API SAX. Θα χρησιμοποιήσουμε την έκδοση 2 (βλ. Πόρους) για τα παραδείγματα μας. Η έκδοση 2 χρησιμοποιεί διαφορετικά ονόματα κλάσης και μεθόδου από την έκδοση 1, αλλά η δομή του κώδικα είναι η ίδια.

Το SAX είναι ένα API, όχι ένα πρόγραμμα ανάλυσης, οπότε αυτός ο κώδικας είναι γενικός σε όλους τους αναλυτές XML. Για να λάβετε τα παραδείγματα για εκτέλεση, θα χρειαστεί να αποκτήσετε πρόσβαση σε ένα πρόγραμμα ανάλυσης XML που υποστηρίζει SAX v2. Χρησιμοποιώ το πρόγραμμα ανάλυσης του Apache's Xerces. (Δείτε τους πόρους.) Ανατρέξτε στον οδηγό έναρξης του αναλυτή σας για λεπτομέρειες σχετικά με την επίκληση ενός αναλυτή SAX.

Η προδιαγραφή SAX API είναι αρκετά απλή. Περιλαμβάνει πολλές λεπτομέρειες, αλλά πρωταρχικό καθήκον είναι να δημιουργήσει μια κλάση που εφαρμόζει το Περιεχόμενο Χειριστής διεπαφή, μια διεπαφή επανάκλησης που χρησιμοποιείται από το πρόγραμμα ανάλυσης XML για να ειδοποιεί το πρόγραμμά σας για συμβάντα SAX, όπως αυτά βρίσκονται στο έγγραφο XML.

Το SAX API παρέχει επίσης βολικά ένα Προεπιλεγμένος χειριστής κλάση εφαρμογής για το Περιεχόμενο Χειριστής διεπαφή.

Μόλις εφαρμόσετε το Περιεχόμενο Χειριστής ή επέκτεινε το Προεπιλεγμένος χειριστής, πρέπει να κατευθύνετε μόνο το πρόγραμμα ανάλυσης XML για να αναλύσετε ένα συγκεκριμένο έγγραφο.

Το πρώτο μας παράδειγμα επεκτείνει το Προεπιλεγμένος χειριστής για να εκτυπώσετε κάθε συμβάν SAX στην κονσόλα. Αυτό θα σας δώσει μια αίσθηση για τα γεγονότα SAX που θα δημιουργηθούν και με ποια σειρά.

Για να ξεκινήσετε, εδώ είναι το δείγμα εγγράφου XML που θα χρησιμοποιήσουμε στο πρώτο μας παράδειγμα:

   Μπομπ Νέα Υόρκη 

Στη συνέχεια, βλέπουμε τον πηγαίο κώδικα για τον κώδικα χαρτογράφησης XML του πρώτου παραδείγματος:

εισαγωγή org.xml.sax. *; εισαγωγή org.xml.sax.helpers. *; εισαγωγή java.io. *; δημόσια κλάση Το Παράδειγμα1 επεκτείνει το DefaultHandler {// Παράκαμψη μεθόδων της κατηγορίας DefaultHandler // για να λάβει ειδοποίηση για SAX Events. // // Δείτε το org.xml.sax.ContentHandler για όλες τις διαθέσιμες εκδηλώσεις. // public void startDocument () ρίχνει το SAXException {System.out.println ("SAX Event: START DOCUMENT"); } public void endDocument () ρίχνει το SAXException {System.out.println ("SAX Event: END DOCUMENT"); } public void startElement (String namespaceURI, String localName, String qName, Attributes attr) ρίχνει το SAXException {System.out.println ("SAX Event: START ELEMENT [" + localName + "]"); // Επίσης, ας εκτυπώσουμε τα χαρακτηριστικά εάν // υπάρχουν κάποια ... για (int i = 0; i <attr.getLength (); i ++) {System.out.println ("ATTRIBUTE:" + attr.getLocalName ( i) + "VALUE:" + attr.getValue (i)); }} public void endElement (String namespaceURI, String localName, String qName) ρίχνει το SAXException {System.out.println ("SAX Event: END ELEMENT [" + localName + "]"); } δημόσιοι άκυροι χαρακτήρες (char [] ch, int start, int length) ρίχνει το SAXException {System.out.print ("SAX Event: CHARACTERS ["); δοκιμάστε το {OutputStreamWriter outw = new OutputStreamWriter (System.out); outw.write (ch, έναρξη, μήκος); outw.flush (); } catch (Εξαίρεση e) {e.printStackTrace (); } System.out.println ("]"); } public static void main (String [] argv) {System.out.println ("Παράδειγμα1 SAX Events:"); δοκιμάστε {// Δημιουργία προγράμματος ανάλυσης SAX 2 ... XMLReader xr = XMLReaderFactory.createXMLReader (); // Ορίστε το ContentHandler ... xr.setContentHandler (νέο Παράδειγμα1 ()); // Αναλύστε το αρχείο ... xr.parse (νέο InputSource (νέο FileReader ("Example1.xml"))); } catch (Εξαίρεση e) {e.printStackTrace (); }}} 

Τέλος, εδώ είναι η έξοδος που δημιουργείται εκτελώντας το πρώτο παράδειγμα με το δείγμα εγγράφου XML:

Παράδειγμα1 Εκδηλώσεις SAX: Εκδήλωση SAX: ΕΝΑΡΞΗ ΕΓΓΡΑΦΟΥ SAX Εκδήλωση: ΕΝΑΡΞΗ ELEMENT [απλή] ΑΞΙΟΛΟΓΗΣΗ: ημερομηνία ΑΞΙΑ: 7/7/2000 SAX Event: CHARACTERS [] SAX Event: START ELEMENT [name] SAX Event: CHARACTERS [Bob] SAX Event : END ELEMENT [name] SAX Event: CHARACTERS [] SAX Event: START ELEMENT [location] SAX Event: CHARACTERS [New York] SAX Event: END ELEMENT [location] SAX Event: CHARACTERS [] SAX Event: END ELEMENT [απλό] SAX Event: ΤΕΛΟΣ ΕΓΓΡΑΦΟΥ 

Όπως μπορείτε να δείτε, ο αναλυτής SAX θα καλέσει τον κατάλληλο Περιεχόμενο Χειριστής μέθοδος για κάθε συμβάν SAX που ανακαλύπτει στο έγγραφο XML.

Γειά σου Κόσμε

Τώρα που καταλαβαίνουμε το βασικό μοτίβο του SAX, μπορούμε να αρχίσουμε να κάνουμε κάτι ελαφρώς χρήσιμο: να εξαγάγουμε τιμές από το απλό έγγραφο XML και να δείξουμε το κλασικό πρόγραμμα hello world.

$config[zx-auto] not found$config[zx-overlay] not found