Web Services. Java-API-JAXP

Web – Services Java-API-JAXP Dokumentation zum Referat „Java-API-JAXP“ Referenten : Ø Mark Vackiner Ø Fares Abdelmounaim Ø Thomas Hahne Ø Dominik ...
Author: Ina Berger
0 downloads 3 Views 2MB Size
Web – Services

Java-API-JAXP

Dokumentation zum Referat „Java-API-JAXP“

Referenten : Ø Mark Vackiner Ø Fares Abdelmounaim Ø Thomas Hahne Ø Dominik Hanft Ø Martin Simmermacher

Erstellt von Martin Simmermacher Mittwoch, 4. Dezember 2002

-2-

Inhalt : 1. Einführung 1.1. Web-Services 1.2. Java-API 1.3. Parser 2. JAXP 2.1. Bestandteile 2.2. Vorraussetzung des Parsers 2.3. Grafische Darstellung 3. SAX 3.1. Funktionsweise 3.2. Handler 3.3. Beispiel 3.3.1. Funktion 3.3.2. Quell-Code 4. DOM 4.1. Funktionsweise 4.2. Spezifikation 4.3. Beispiel 4.3.1. Funktion 4.3.2. Quell-Code 5. XSLT 6. Anhang 6.1. SAX 6.2. DOM

-3-

1. Einführung 1.1. Web-Services Durch das Internet und die Fortschritte im Bereich der Netztechnologien sind Services on Demand möglich: Nutzung von Diensten von überall, zu jeder Zeit und mit jedem Endgerät. Die Realisierung solcher Web Services erfordert neue Techniken und Protokolle sowie eine Entwicklungsinfrastruktur, die auf Standards beruht. Web Services sind dazu da um konsumiert zu werden! Die Erstellung eines Web Services ist Dank des Microsoft SOAP Toolkits relativ einfach. Nach der Erstellung des Web Service soll der Client aber auch die Dienste benutzen, d.h. konsumieren können. Anhand eines einfachen Beispiels, soll dies mit Hilfe des SOAP Toolkits dargestellt werden. Der "Konsum"-Prozess beginnt mit einem Request des Clients. Eben dieser Request wird vom SoapClient Objekt entgegengenommen und erstellt einen SOAP Request der dem Web Server übergeben wird. Der Server bearbeitet dann den Request, führt die erhaltenen Anweisungen aus, und schickt das Ergebnis als SOAP Response wieder zurück zum Client. Dort formuliert der SoapClient aus der SOAP Response eine, für den Benutzer des Web Service lesbare Anwort, die das Ergebnis aus der Prozedur enthält.

Bildlich gesprochen passiert also folgendes:

-4-

1.2. Java-API Hinter dem Namen API verbirgt sich das Application Programming Interface, welches folgende Punkte in sich vereinigt : l l l l

Sammlung von Schnittstellen Erleichtert die Erstellung von Software Vereinfacht Zugriffe auf Bestandteile des Systems Entwickler muss keine speziellen Systemkenntnisse haben

1.3. Parser Ein Parser ist eine Software oder ein Teil davon, die den Datenstrom eines Dokumentes analysiert und entsprechend der Syntax aufbereitet. Beim Parsing werden die Informationen des Dokumentes in die Elemente gefiltert, in die die Informationen strukturiert sind. Um z.B. ein XML-Dokument zu parsen, erzeugt man sich zunächst eine Instanz eines SAXParsers. Dies geschieht über die ParserFactory, die gemäß der Fabrikmethode den Erzeugungsprozeß des Parsers kapselt. Der Parser darf aus einem beliebigen XML-ParserPaket kommen und muß sich an die SAX-Spezifikation halten.

(Vorraussetzungen für einen Parser sh. Kap. 2.2. Vorraussetzungen des Parsers.)

-5-

2. JAXP JAXP wurde von einem Projektteam unter der Führung von SUN entwickelt und stellt Standard-Schnittstellen zum Parsen und Manipulieren von XML-Dokumenten zur Verfügung. Allerdings überläßt es die Wahl eines bestimmten Parsers dem Programmierer, der über einen sogenannten Plugability Layer den zu benutzenden Parser für das Parsen festlegen kann. Das ganze Paket ist ein "Java Optional Package" und hat den Paketnamen javax.xml.parsers. Wie man an dem javax Präfix sieht, gehört es damit schon zu den Standarderweiterungen des JDK( wie z.B. auch die swing-Pakete im Paket javax.swing.*), wird zur Zeit aber noch nicht zusammen mit dem JSDK ausgeliefert.

2.1. Bestandteile Zur Zeit besteht JAXP aus 6 Klassen, davon sind 4 abstrakt und definieren die Schnittstellen für das Erzeugen eines SAXParsers bzw. DOMBuilders, sowie für das Arbeiten mit Instanzen von ihnen. Die anderen zwei Klassen sind zur Fehlerbehandlung vorgesehen. •

SAXParserFactory : ist eine Klasse, nach dem Designmuster der Fabrikmethode, die es Anwendungen erlaubt einen Parser nach der SAX-Spezifikaton zu konfigurieren und eine Instanz zu erhalten.



SAXParser: kapselt den benutzten SAX-Parser, der gemäß des org.xml.saxParser Interfaces implementiert sein muß. Methoden: parse und Infos über Parserstate. Ein Aufruf von SAXParserFactory.newInstance() gibt immer eine Instanz dieser Klasse zurück.



DocumentBuilderFactory : ähnlich der SAXParserFactory, nur wird hier ein Parser instanziert und konfiguriert, der ein XML-Dokument parsed und ein DOM-Modell liefert.



DocumentBuilder: kapselt den benutzten DOM-Builder, der von der DocumentBuilderFactory bei Aufruf von newInstance() zurückgegeben wird.



FactoryConfigurationError: Falls es irgendein Problem bei der Konfiguration der Factory-Klassen gibt, wird dieser Fehler aufgerufen.



ParserConfigurationException: Diese Exception tritt auf, wenn die Factory den Parser nicht mit den vorgegebenen Parametern konfigurieren konnte.

-6-

2.2. Vorraussetzungen des Parsers Um einen Parser in das JAXP-Paket "pluggen" zu können, muß dieser einige Voraussetzungen erfüllen: •

Er muß als Character Set encodings mindestens ascii, UTF-8 und UTF-16 unterstützen



Er muß ein Dokument auf seine Wohlgeformtheit überprüfen können



Er muß ein Dokument auf seine Gültigkeit anhand der DTD überprüfen können

2.3. Grafische Darstellung

SAX Applikation

JAXP XSLT DOM

Plug in Implemtationen verschiedener Hersteller

Kompilierte Anwendung

-7-

3. SAX SAX steht für "Simple API for XML" und definiert Schnittstellen für das Parsen von XMLDokumenten. Es ist kein W3C-Standard, sondern wurde vo n der XML-DEV Mailinglist entwickelt und Anfang 1998 in der Version 1.0 herausgebracht. Zur Zeit ist die Version 2.0 aktuell. Das SAX-API stellt einen Mechanismus zur seriellen Verarbeitung von XML-Dokumenten zur Verfügung. Das heißt, dass ein Dokument Element um Element abgearbeitet wird. Die Kommunikation mit anderen Anwendungen wird dabei über sogenannte Handler abgewickelt, weshalb man auch von einem ereignisgesteuerten Protokoll spricht.

Die folgende Grafik illustriert dies:

-8-

3.1. Funktionsweise Um ein XML-Dokument zu parsen, erzeugt man sich zunächst eine Instanz eines SAXParsers. Dies geschieht über die ParserFactory, die gemäß der Fabrikmethode den Erzeugungsprozeß des Parsers kapselt. Der Parser darf aus einem beliebigen XML-ParserPaket kommen und muß sich an die SAX-Spezifikation halten. Danach muß man die jeweiligen Handler(entweder generische von einem XML-Parser, oder Handler, die man selbst gemäß den durch SAX gegebenen Interfaces implementiert hat) erzeugen und beim Parser registrieren. Zum Schluß ruft man die Methode parse des Parsers mit dem zu parsenden XMLDokument als Parameter auf. Der Parser wird nun das Dokument sequentiell lesen und je nach Element, das er liest, bestimmte callback-Methoden in den Handlern aufrufen. Über diese und vor allem den DocumentHandler läßt sich die Verarbeitung des XMLDokuments dann steuern.

3.2. Handler Das SAX-API definiert folgende Handler zur Verarbeitung eines XML-Dokuments: •

DocumentHandler: Dies ist der wichtigste Handler zur Verarbeitung überhaupt. In ihm werden die Methoden startDocument und endDocument implementiert, die jeweils zu Beginn und zum Ende eines Dokuments auftreten. Desweiteren gibt es die Methoden startElement und endElement, die aufgerufen werden, wenn der Parser ein einleitendes Tag bzw. ein schließendes Tag erkennt. Erkennt der Parser z.B. ein einleitendes Tag, wird die Methode startElement mit dem Namen des Tags und sämtlichen Attributwertpaaren als Parameter aufgerufen. In dieser Methode kann der Programmierer nun die Verarbeitung des Tags steuern, z.B. Name und Attribute des Tags ausgeben. Analog dazu wird die Methode endElement aufgerufen, wenn der Parser ein schließendes Tag erkennt. Erkennt der Parser hingegen freien Text, der zwischen Tags steht, wird die Methode characters aufgerufen, findet er eine Processing Instruction die Methode processingInstruction. Außerdem gibt es noch die Methode setDocumentLocator, mit der ein Locator-Objekt an den DocumentHandler übergeben wird. Dieser Locator gibt an, wo der Parser sich gerade im XMLDokument befindet. Zur Behandlung von Whitespace gibt es die Methode ignorableWhitespace.



ErrorHandler: Dieser Handler behandelt alle Fehler, die beim Parsen auftreten. Dafür gibt es die Methoden warning, error und fatalError, die je nach Schwere des Fehlers beim Parsen aufgerufen werden. Als Parameter erhalten diese Methoden eine SAXParseException, in der nähere Angaben zur Art des Fehlers und der Position, an der er aufgetreten ist, gespeichert sind. Das SAX-API liefert zwar einen Default ErrorHandler in der HandlerBase Klasse, dieser wirft aber nur Exceptions bei fatalErrors, andere Fehler ignoriert er. -9-

Um Fehler in XML-Dokumenten zu erkennen, sollte man hier also auf jeden Fall seinen eigenen ErrorHandler mit speziellen Fehlerbehandlungen schreiben und beim Parser registrieren. •

DTDHandler: Dieser Handler kommt zur Anwendung, wenn der Parser in einer DTD auf ein unparsed entity, also Binärdaten mit einer zugehörigen Notation, trifft. Er ruft dann entweder die Methode unparsedEntityDecl oder notationDecl auf, in der der Programmierer seine eigene Behandlung der unparsed entities durchführen kann.



EntityResolver: Der EntityResolver wird benötigt, wenn der Parser auf Referenzen zu externen Dateien, z.B. DTD's trifft, und diese lesen muß. Der Parser ruft dann die einzige Methode dieses Handlers, resolveEntity auf, die aus einer öffentlichen ID(URN=Universal Resource Name) eine System ID(URL=Universal Resource Locator) macht.

3.3. Beispiel Im Beispiel-Programm soll gezeigt werden, wie mit Hilfe des SAX-API der Inhalt einer XML-Datei eine formatierte Ausgabe auf einem Medium generiert werden kann.

3.3.1. Funktion Das Programm liest den Inhalt der XML-Datei1 , der eine Mediensammlung repräsentieren soll. Exemplarisch sind im Beispiel 2 CDs mit entsprechenden Titeln gefüllt. Mit Hilfe der SAX - Bibliotheken wird der Inhalt formatiert auf einem Text-Ausgabemedium ausgegeben (im Beispiel: JTextField). Die eigentliche Aufgabe wird hier von der Call- Back Funktion "startElement(..)" gelöst. Sie unterscheidet anhand des Tag-Namens, ob es sich bei dem gerade eingelesenen Tag um das "CD" oder "Track" – Starttag handelt. Je nachdem werden die weiteren, in den Tag Argumenten, enthaltenen Informationen entweder als CD-Überschrift oder die einzelnen Daten formatiert als CD Track "Nr. Titel - Interpret (Zeit)" ausgegeben.

1

sh. Kapitel 6.1.

- 10 -

3.3.2. Quell-Code Klasse DemoApplication: package webservices_jaxp; import javax.swing.UIManager; import java.awt.*; /** * Überschrift: WebServices - JAXP Eingabe * Beschreibung: * Copyright: Copyright (c) 2002 * Organisation: * @author Dominik Hanft * @version 1.0 */ public class DemoApplication_JAXP { private boolean packFrame = false; public DemoApplication_JAXP() { frmMain frame = new frmMain(); if (packFrame) { frame.pack(); } else { frame.validate(); } /* * Das Fenster zentrieren */ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension frameSize = frame.getSize(); if (frameSize.height > screenSize.height) { frameSize.height = screenSize.height; } if (frameSize.width > screenSize.width) { frameSize.width = screenSize.width; } frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2); frame.setVisible(true); } public static void main(String[] args) { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch(Exception e) { e.printStackTrace(); } new DemoApplication_JAXP(); } }

- 11 -

Klasse Echo: package webservices_jaxp; import import import import import

java.io.*; org.xml.sax.*; org.xml.sax.helpers.DefaultHandler; javax.xml.parsers.SAXParserFactory; javax.xml.parsers.SAXParser;

/** * Überschrift: WebServices - JAXP SAX Eingabe * Beschreibung: * Copyright: Copyright (c) 2002 * Organisation: * @author Dominik Hanft * @version 1.0 */ public class Echo extends DefaultHandler{

static private javax.swing.JTextArea out; /** * Textarea als Ausgabemedium übernehmen */ public Echo(javax.swing.JTextArea myWriter) { out = myWriter; } /** * Gibt den übergeben String auf dem Ausgabemedium aus * @param s auszugebener String */ private void emit(String s) throws SAXException { try { out.append(s); out.repaint(); } catch (Exception e) { throw new SAXException("Ausgabefehler!", e); } } /** * Gibt einen Zeilenumbruch auf dem Ausgabemedium aus */ private void nl() throws SAXException { String lineEnd = System.getProperty("line.separator"); try { out.append(lineEnd); } catch (Exception e) { throw new SAXException("I/O error", e); } }

- 12 -

/** * Gibt einen Info-Text beim Start des Parsers aus */ public void startDocument() throws SAXException { emit("
Start ... -->");

} /** * Gibt einen Info-Text beim Beenden des Parsers aus */ public void endDocument() throws SAXException { emit(""); nl(); } public void startElement(String namespaceURI, String sName, // simple name String qName, // qualified name Attributes attrs) throws SAXException { String eName = sName; // element name if ("".equals(eName)) eName = qName; // not namespaceAware if (eName=="CD") { // CD Titel ausgeben emit(attrs.getValue("Name")); nl(); for (int i = 0; i < attrs.getValue("Name").length(); i++) { emit("-"); } nl(); } else if (eName=="Track") { // einzelnen Track mit Länge ausgeben emit(attrs.getValue("Nr") + ": "); emit(attrs.getValue("Name") + " - " + attrs.getValue("Interpret")); emit(" ("+attrs.getValue("Länge")+")"); nl(); } } public void endElement(String namespaceURI, String sName, // simple name String qName // qualified name ) throws SAXException {

- 13 -

String eName = sName; // element name if ("".equals(eName)) eName = qName; // not namespaceAware if (eName=="CD") { nl(); } } }

Klasse frmMain:

package webservices_jaxp; import import import import import import import import import import

java.awt.*; java.awt.event.*; javax.swing.*; java.io.*; java.util.*; org.xml.sax.*; org.xml.sax.helpers.DefaultHandler; javax.xml.parsers.SAXParserFactory; javax.xml.parsers.ParserConfigurationException; javax.xml.parsers.SAXParser;

/** * Überschrift: WebServices - JAXP Eingabe * Beschreibung: * Copyright: Copyright (c) 2002 * Organisation: * @author Dominik Hanft * @version 1.0 */ public class frmMain extends JFrame { private JPanel contentPane; static private Writer out; private JPanel jPanel1 = new JPanel(); private JButton cmdStart = new JButton(); private JButton cmdExit = new JButton(); private BorderLayout borderLayout1 = new BorderLayout(); private JPanel jPanel2 = new JPanel(); private BorderLayout borderLayout2 = new BorderLayout(); private JScrollPane jScrollPane1 = new JScrollPane(); private JTextArea taAusgabe = new JTextArea(); private JButton cmdClear = new JButton(); private JPanel jPanel3 = new JPanel(); private JTextField tfFileName = new JTextField(); private JButton jButton1 = new JButton(); public frmMain() { enableEvents(AWTEvent.WINDOW_EVENT_MASK); try { jbInit(); } catch(Exception e) { e.printStackTrace(); } }

- 14 -

private void jbInit() throws Exception

{

//setIconImage(Toolkit.getDefaultToolkit().createImage(frmMain.class.getRes ource("[Ihr Symbol]"))); contentPane = (JPanel) this.getContentPane(); contentPane.setLayout(borderLayout1); this.setSize(new Dimension(600, 500)); this.setTitle("JAXP Demo"); cmdStart.setText("Start Parser"); cmdStart.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { cmdStart_actionPerformed(e); } }); cmdExit.setText("Ende"); cmdExit.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { cmdExit_actionPerformed(e); } }); jPanel2.setLayout(borderLayout2); cmdClear.setText("Clear"); cmdClear.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { cmdClear_actionPerformed(e); } }); tfFileName.setFont(new java.awt.Font("Dialog", 0, 12)); tfFileName.setPreferredSize(new Dimension(400, 24)); tfFileName.setText("C:\\Dokumente und Einstellungen\\dhanft\\jbproject\\WebServices_JAXP\\beispiel.xml"); tfFileName.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { tfFileName_actionPerformed(e); } }); jButton1.setText("Browse"); jButton1.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { jButton1_actionPerformed(e); } }); contentPane.add(jPanel1, BorderLayout.NORTH); jPanel1.add(cmdStart, null); jPanel1.add(cmdClear, null); jPanel1.add(cmdExit, null); contentPane.add(jPanel2, BorderLayout.CENTER); jPanel2.add(jScrollPane1, BorderLayout.CENTER); contentPane.add(jPanel3, BorderLayout.SOUTH); jPanel3.add(tfFileName, null); jPanel3.add(jButton1, null); jScrollPane1.getViewport().add(taAusgabe, null); } protected void processWindowEvent(WindowEvent e) { super.processWindowEvent(e); if (e.getID() == WindowEvent.WINDOW_CLOSING) { System.exit(0); } }

- 15 -

private void echoStart() throws Exception { // Instanz der eigenen Klasse als SAX event handler erzeugen DefaultHandler myHandler = new webservices_jaxp.Echo(taAusgabe); // Instanz der SAX Factory erzeugen SAXParserFactory myFactory = SAXParserFactory.newInstance(); // Instance des SAX Parsers von der Factory holen SAXParser saxParser = myFactory.newSAXParser(); try { // XML Datei parsen saxParser.parse( new File(tfFileName.getText()), myHandler ); } catch (Throwable t) { t.printStackTrace(); } } void cmdStart_actionPerformed(ActionEvent e) { try { echoStart(); } catch (Exception ex) { ex.printStackTrace(); } } void cmdExit_actionPerformed(ActionEvent e) { System.exit(0); } void cmdClear_actionPerformed(ActionEvent e) { taAusgabe.setText(""); } void jButton1_actionPerformed(ActionEvent e) { java.awt.FileDialog myFileChooser = new java.awt.FileDialog(this,"XML File auswählen",1); myFileChooser.setMode(java.awt.FileDialog.LOAD); myFileChooser.show(); tfFileName.setText(myFileChooser.getDirectory() + myFileChooser.getFile()); } void tfFileName_actionPerformed(ActionEvent e) { } }

- 16 -

4. DOM Das Document Object Model (DOM) ist eine allgemeine Beschreibung eines Application Programming Interface (API) für HTML und XML Dokumente. Es beschreibt die innere Struktur von Dokumenten und die Art und Weise wie auf solche Dokumente zugegriffen werden kann, bzw. wie diese bearbeitet werden. Programmierer können mit Hilfe des DOM komplette Dokumente erstellen bzw. deren Struktur verändern indem einzelne Elemente hinzugefügt, entfernt oder bearbeitet werden. Damit das DOM auf vielen verschiedenen Plattformen eingesetzt werden kann, wurde die Spezifikation in der plattformunabhängigen Sparche IDL der Object Management Groupe (OMG) verfasst. (IDL = Interace Definition Language). IDL wird in der CORBA Spezifikation beschrieben. Das DOM ist daher nur eine Vorlage, die erst für verschiedene Programmierumgebungen implementiert werden muß. Für einige Sprachen wie z.B. Java, C++, ECMAScript und Perl sind DOM Impementierungen frei verfügbar.

Geschichte Das DOM wurde und wird vom World Wide Web Consortium (W3C) entwickelt. Der Anfang wurde im September 1997 mit einem Dokument (DOM requirements document) gemacht, welches prinzipiell die Anforderungen an eine solche API festhält. Von diesen Vereinbarungen ausgehend entstand das DOM Level 1, welches im Oktober 1998 in der ersten Version fertig wurde. Im Dezember des gleichen Jahres veröffentlichte das W3C das erste ``public draft'' der DOM Level 2 Spezifikation. Laut W3C wird DOM Level 2 in kürze vollendet sein. Im Mai 2000 entstand eine erweiterte Version des DOM requirements document. Dieses bildet die Grundlage für die nächste DOM Generation, DOM Level 3. Ein ``public draft'' hat das W3C bereits im September 2000 veröffentlicht. Die einzelnen Levels der DOM Spezifikation sind untereinander abwärtskompatibel. Sie unterscheiden sich nur in der Größe des Funktionumfanges.

Was ist DOM? Die Abkürzung DOM steht für Document Object Model. Eine Übersetzung ins deutsche bedeutet soviel wie Objektorientiertes Dokumentenmodell. Unter der Abkürzung DOM verbergen sich jedoch zwei Bedeutungen. Spricht man von diesem so muß unterschieden werden welche der beiden Bedeutungen gerade gemeint ist. Es ist zum einen ein Objektorientiertes Modell zur logischen Darstellung von Informationen aller Art, und zum anderen eine Schnittstellendefinition die es erlaubt in einem solchen Modell sich zu bewegen, Informationen aus dem Modell zu lesen und dieses Modell zu manipulieren. Unter Manipulation versteht man das Hinzufügen, Verändern oder Entfernen von Informationen aus einem solchen Modell.

- 17 -

4.1. Funktionsweise Das DOM definiert in erster Linie eine logische Struktur für XML - Dokumente. Im allgemeinen wird jede Form von Daten, die mit Hilfe von XML strukturiert werden kann als Dokument im Sinne des DOM angesehen. Das bedeutet dass auch HTML - Dokumente gültige Dokumente im Sinne des DOM sind, da HTML durch eine passende XML Sprachdefinition abgebildet werden kann. Welche Informationen und wie man Informationen aller Art in XML strukturieren kann und damit als ein DOM ansehen kann soll der Abschnitt Daten in "DOM - Form" verdeutlichen.

4.2. Spezifikation

Es wird festgelegt, wie ein DOM Client mit einer DOM-Implementierung über Interfaces kommuniziert.

- 18 -

4.3. Beispiel Im Beispiel-Programm soll gezeigt werden, wie ein DOM Tree aus einem XML-Dokument aufgebaut und ein XML-Dokument aus eine m DOM Tree generiert werden kann.

4.3.1. Funktion Zuerst wird ein Fenster mit zwei "Textfeldern" erzeugt. Über einen entsprechenden Button kann man eine beliebige XML-Datei2 auswählen, die dann im linken Textfeld erscheint. Mit dem Button "Transformieren" (in der Mitte des Fensters), wird der Inhalt der zuvor ausgewählten Datei in ein temporäres File zwischengespeichert und die Methode Parse() der Klasse "JAXPDOM" aufgerufen. Als Parameter werden boolsche Werte übergeben, welche die Flags zur Einstellung des Parsers repräsentieren. Die Datei "temp.dat" wird nun geparst und ein DOM-Tree aufgebaut. Mit Hilfe der Methode "knotenAusgeben()" wird der Baum, beginnend mit seinem Wurzelknoten grafisch zur Ausgabe gebracht, und zwar im rechten Feld, in Form eines JTrees aus der Swing-Bibliothek. Über diesem Feld befindet sich ein weiterer Button, welcher mit Hilfe eines XSLT-Wandlers den DOM-Tree zurück in ein XML-Dokument transformiert. Der Benutzer kann für dieses Dokument einen beliebigen Namen auswählen.

4.3.2. Quell-Code /////////////////////////////////////////////////////////////////////////////////////// // Beispiel für eine JAVA-Anwendung mit JAXP. // // Beinhaltet: // // - DOM Tree aus einem XML-Dokument aufbauen // // - XML-Dokument aus einem DOM Tree generieren // // im Rahmen des Gruppenreferats zum Thema JAXP // // Autor: Mark Vackiner // // Datum: 02.11.2002 // // Dozent: Prof. Dr. Alois Schütte // ///////////////////////////////////////////////////////////////////////////////////////

import java.awt.Frame; import java.awt.*; import java.awt.event.*; import java.awt.GridBagLayout.*; import java.io.*; 2

sh. Kapitel 6.2.

- 19 -

import javax.swing.*; import javax.swing.tree.*; // Imports fuer JAXP import javax.xml.parsers.*; import org.xml.sax.*; import org.w3c.dom.*; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; public class JAXP_mit_DOM extends Frame { // Klassenweit gueltige Variablen private TextField tf_datei; private TextArea ta_links; private JTree ta_rechts; private JAXPDOM jaxpdom; private Checkbox box1, box2, box3, box4, box5, box6; private Frame myFrame; public static void main(String args[]) { JAXP_mit_DOM beispiel = new JAXP_mit_DOM("JAXP mit DOM"); beispiel.setSize(800,600); beispiel.show(); } public JAXP_mit_DOM(String Titel) { super(Titel); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent event) { dispose(); System.exit(0); } }); myFrame = this; // Baum aus der Swing- Bibliothek mit Wurzelknoten 'root' erze ugen, // mit ScrollPane versehen und dem Panel hinzufuegen DefaultMutableTreeNode root; root = new DefaultMutableTreeNode("Document"); ta_rechts = new JTree(root); - 20 -

Panel cp = new Panel(); cp.setLayout(new BorderLayout()); cp.add(new JScrollPane(ta_rechts), BorderLayout.CENTER); cp.setSize(new Dimension(200,300));

// AWT-Elemente fuer die GUI erzeugen tf_datei = new TextField(25); ta_links=new TextArea(33,45); Panel panel = new Panel(); Label label = new Label("Pfad und Name der Datei:"); Button b_laden = new Button("Laden"); Button b_mitte=new Button("Transformieren >>"); Button b_speichern = new Button("Als XML-Dokument speichern"); tf_datei.setText(""); Panel p_unten = new Panel(); // Checkboxen erzeugen und auf unteres Panel platzieren box1 = new Checkbox("Validating"); box2 = new Checkbox("NamespaceAware"); box3 = new Checkbox("IgnoringComments"); box4 = new Checkbox("IgnoringWhitespace"); box5 = new Checkbox("Coalescing"); box6 = new Checkbox("ExpandEntityReferences"); p_unten.add(box1); p_unten.add(box2); p_unten.add(box3); p_unten.add(box4); p_unten.add(box5); p_unten.add(box6); // Objekt der Klasse JAXPDOM erzeugen, in der JAXP implementiert ist jaxpdom = new JAXPDOM(ta_rechts, root); // Elemente zur Dateiauswahl auf Panel abbilden panel.add(label); panel.add(tf_datei); panel.add(b_laden); // Hintergrundfarbe einstellen (freundliches Grau) setBackground(new Color(236,233,215));

// Layoutmanager vom Typ GridBagLayout mit Eigenschaften erzeugen // und auf Hauptfenster anwenden GridBagLayo ut layout = new GridBagLayout(); GridBagConstraints constraints = new GridBagConstraints(); setLayout(layout); // Platzierung Panel fuer Dateihandling constraints.gridy = 0; - 21 -

constraints.gridx = 0; constraints.gridheight = 1; constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(2, 2, 2, 2); layout.setConstraints(panel, constraints); add(panel); // Platzierung Button zum Transformieren und Speichern einer Datei constraints.gridy = 0; constraints.gridx = 2; constraints.gridheight = 1; constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(2, 2, 2, 2); constraints.gridwidth = GridBagConstraints.REMAINDER; layout.setConstraints(b_speichern, constraints); add(b_speichern); // Platzierung TextArea ta_links zur Darstellung von Dateiinhalten constraints.gridy = 1; constraints.gridx = 0; constraints.weightx = 1; constraints.weighty = 1; constraints.fill = GridBagConstraints.BOTH; constraints.gridwidth = 1; layout.setConstraints(ta_links,constraints); add(ta_links); // Platzierung Button b_mitte constraints.gridy = 1; constraints.gridx = 1; constraints.weightx = 0; constraints.fill = GridBagConstraints.NONE; constraints.gridwidth = 1; layout.setConstraints(b_mitte, cons traints); add(b_mitte); // Platzierung JTree ta_rechts constraints.gridy = 1; constraints.gridx = 2; constraints.weightx = 1; constraints.fill = GridBagConstraints.BOTH; constraints.gridwidth = 1; layout.setConstraints(cp,constraints); add(cp); // Platzierung Panel p_unten constraints.gridheight = 1; constraints.gridy = 2; constraints.gridx = 0; constraints.weighty = 0; constraints.gridwidth = GridBagConstraints.REMAINDER; - 22 -

constraints.fill = GridBagConstraints.NONE; constraints.anchor = GridBagConstraints.WEST; layout.setConstraints(p_unten,constraints); add(p_unten);

// ActionListener fuer Button b_laden ///////////////////////////////////////////////////////////// b_laden.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // Fenster 'dlgLaden' zum Auswaehlen einer Datei erzeugen und // auf dem Bildschirm anzeigen FileDialog dlgLaden = new FileDialog(myFrame,"Datei laden",FileDialog.LOAD); dlgLaden.show(); // Wenn nach Schliessen des Fensters keine Datei ausgewaehlt // wurde, abbrechen, sonst Pfad und Dateiname in Textfeld // 'tf_datei' einlesen if (dlgLaden.getFile() != null) { tf_datei.setText(new String (dlgLaden.getDirectory()+dlgLaden.getFile())); // Der Inhalt der zuvor ausgewaehlten Datei wird ausgelesen und // im linken Textfeld 'ta_links' zur Anzeige gebracht try { FileInputStream lesen = new FileInputStream(tf_datei.getText()); BufferedInputStream temp = new BufferedInputStream(lesen); byte inhalt[] = new byte[4096]; while (temp.available() > 0) { temp.read(inhalt); } ta_links.setText(new String(inhalt)); } catch (IOException ex) { System.err.println(ex.toString()); } } } });

- 23 -

// ActionListener fuer Button b_speichern ///////////////////////////////////////////////////////////// b_speichern.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // Fenster 'dlgLaden' zum Auswaehlen einer Datei, diese // erzeugen und auf dem Bildschirm anzeigen FileDialog dlgSpeichern = new FileDialog(myFrame, "Speichern unter", FileDialog.SAVE); dlgSpeichern.show(); // Wenn ein Name fuer die zu speichernde Datei // ausgewaehlt wurde, wird ein Objekt von der Klasse "File" // erzeugt und der Methode 'transform' der Klasse 'JAXPDOM' // als Parameter übergeben if (dlgSpeichern.getFile() != null) { File f = new File (dlgSpeichern.getFile()); jaxpdom.transform(f); } } }); // ActionListener fuer Button b_mitte //////////////////////////////////////////////////////////// b_mitte.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // Es wird versucht, eine temporaere Datei mit Namen 'temp.dat' // in das aktuelle Verzeichnis zu schreiben. In diese Datei // soll der Inhalt der linken Text-Area geschrieben werden try { FileOutputStream out = new FileOutputStream("temp.dat"); byte[] zeichen = ta_links.getText().getBytes(); out.write(zeichen); } catch (IOException ey) { ey.printStackTrace(); } // Die Methode 'Parse' der Klasse 'JAXPDOM' wird aufgerufen // Die boolschen Werte aus den Checkboxen werden als Parameter // uebergeben jaxpdom.Parse(box1.getState(), box2.getState(), box3.getState(), box4.getState(), box5.getState(), box6.getState()); } }); - 24 -

} } //////////////////////////// Klasse JAXPDOM /////////////////////////////// class JAXPDOM { // Klassenweit gueltige Variablen private JTree tree; private DefaultMutableTreeNode root; private DefaultTreeModel model; private Document doc; public JAXPDOM(JTree ta_rechts, DefaultMutableTreeNode r) { // Klassenweit gueltige Variablen belegen tree = ta_rechts; root = r; model = (DefaultTreeModel)tree.getModel(); } public void Parse (boolean val, boolean nsa, boolean ic, boolean iecw, boolean coal, boolean eer) { // Flags setzen DocumentBuilder parser; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(val); factory.setNamespaceAware(nsa); factory.setIgnoringComments(ic); factory.setIgnoringElementContentWhitespace(iecw); factory.setCoalescing(coal); factory.setExpandEntityReferences(eer); // Die temporäre Datei "tmp.dat" parsen, das Baumdiagramm bis auf den // Wurzelknoten löschen, neu aufbauen und die Anzeige aktualisieren try { parser = factory.newDocumentBuilder(); doc = parser.parse(new File("temp.dat")); root.removeAllChildren(); knotenAusgeben(doc,root); model.reload(); } // Ausnahmebehandlung catch (SAXException e) { System.out.println("Fehler: " + e); } catch (IOException e) { System.out.println("I/O-Fehler: " + e); - 25 -

} catch (ParserConfigurationException e) { System.out.println("Fehler beim Laden d. Parser-Implementation: " + e); } } private void knotenAusgeben(Node knoten, DefaultMutableTreeNode parent) { // Die Methode "knotenAusgeben()" durchlaeft den zuvor // erzeugten DOM-Tree, beginnened mit der Wurzel, indem sie sich // selbst aufruft, wenn ein Knoten weitere "Kinder" besitzt. // Switch-Case unterscheidet den Knotentyp und baut dementsprechend // einen Grafischen Baum der Klasse "JTree" auf. // Die Namen der nachfolgenden Knotentypen sind weitestgehend selbst// erklaerend. Die Verarbeitung im Falle einer Verarbeitungsanweisung // ("PROCESSING_INSTRUCTION_NODE") bleibt zur Vereinfachung unberueck// sichtigt. switch (knoten.getNodeType()) { // Der Wurzelknoten ist das Dokument selbst. Die Wurzel existiert // bereits im JTree, deshalb wird nur nach "Kind-Knoten" gesucht. case Node.DOCUMENT_NODE: DefaultMutableTreeNode child; Document doc=(Document)knoten; knotenAusgeben(doc.getDocumentElement(),root); break; // Ein "ganz normaler" Knoten (XML-Element) case Node.ELEMENT_NODE: String name = knoten.getNodeName(); // Suche nach Attributen NamedNodeMap attribute = knoten.getAttributes(); if (attribute.getLength() != 0) { for (int i=0; i