Tamino XML-Datenbank Technologie Memo April 2005 Dr. Arno Schmidhauser Tamino XML-Datenbank Inhalt 1 2 3 4 5 6 Referenz Einsatzgebiete Features Datenbank-Organisation Kommunikation mit Tamino Abfragesprachen 6.1 XPath, XQuery 6.2 XUpdate 6.3 Trigger 7 Indexe 8 Transaktionsverhalten 9 Entwicklungs-Tools 10 Verschiedenes 11 Beispiel HTTP-Anbindung 12 Beispiel DOM-Anbindung Technologie Memo Arno Schmidhauser 3 3 3 4 5 6 6 6 7 7 8 8 8 9 15 2 Tamino XML-Datenbank 1 Referenz Die folgenden Kapitel beziehen sich auf die XML-Datenbank Tamino, Version 4.2.1, der Firma Software AG, Deutschland: www.tamino.de oder www.softwareag.com. 2 Einsatzgebiete Dokumentzentrierte und semistrukturierte Informationssysteme, beispielsweise elektronische Patientenakte, Ablage von Publikationen, Verträgen, Kundendokumenten usw. Fulltext-Retrieval ist ein Stärke von Tamino. 3 Features Native XML-Datenbank für High End Performance. Transaktionsorientiert, mit vielen Monitoring- und Verwaltungstools. Die Abfragesprache XQuery des W3 Konsortiums wird grösstenteils unterstützt. Der Name 'XQuery' ist nicht zu verwechseln mit 'X-Query', der ältern Abfragesprache von Tamino, die im Wesentlichen eine Erweiterung von XPath 1.0 darstellt. Zusätzlich zu XQuery sind mächtige Funktionen für das FulltextRetrieval verfügbar (allerdings nicht in der Syntax des XQuery Fulltext Standards). Die Funktionen umfassen das Suchen nach benachbarten Worten, phonetische Suche, Stammform-Suche, Thesaurus, Patternmatching. Als Erweiterung zu XQuery wird eine XML-basierte Modifikationssprache angeboten, so dass mit XQuery von Tamino im einheitlichen "Look and Feel" Daten verwaltet werden können, in Analogie zu den SQL-Befehlen select/update/delete/insert. API's für Java, .net, C, PHP und JScript. Java API's: SAX, DOM und DOM4J sowohl für lesenden wie schreibenden Zugriff auf die zugrundeliegende Datenbank. Die zu verarbeitenden Daten können mittels Query vorselektiert und dann geändert oder gelöscht werden. Benutzerverwaltung mit User, Group und ACL's. Die Authorisierung findet auf XML-Knotenebene (!) statt. Authentisierung über Zertifikate via vorgeschalteten Webserver. Technologie Memo Arno Schmidhauser 3 Tamino XML-Datenbank 4 Datenbank-Organisation Auf Ebene Betriebssystem besteht eine 1 zu 1 Beziehung zwischen Datenbank und Prozess. Die Datenbank enthält eine Anzahl so genannter Collections. Eine Collection ist eine Sammlung von XML-Dokumenten. Es gibt System-Collections und es gibt Benutzer-Collections (analog zu relationalen Datenbanken mit System-Tabellen und Benutzer-Tabellen). Datenbank-Serverprozess Datenbank Collection X Schema A Collection Y Schema B Schema C Collection mit a und b Dokumenten Schema D Collection mit c und d Dokumenten Die Hierarchische Organisation ist wie folgt: Datenbank Æ Collection Æ Dokument Æ Inhalt Es können beliebig viele Benutzer-Collections errichtet werden. Für jede Collection können mehrere XML Schema definiert werden. Dokumente in den Collections können, aber müssen nicht einem Schema zugeordnet sein. Ob nur schema-konforme Dokumente zugelassen sind oder nicht, wird beim Erstellen der Collection festgelegt. Ein Dokument ist die Grundeinheit, welche in eine Collection eingefügt, geändert oder gelöscht wird. Beispielsweise werden in einer Collection, welche einen Bücherkatalog darstellt, book-Dokumente eingefügt. Die Schema-Definition in Tamino hat einige Erweiterungen gegenüber der Spezifikation des W3C. Beispielsweise gibt es ein so genanntes doctype-Element, welches den Namen des Root-Elementes eines Dokumentes identifiziert (analog zum DTD Doctype). Ausserdem werden Index-Definitionen, Angaben zur Kompression usw. innerhalb des Schema vorgenommen. Der Namespace tsd: kennzeichnet die Tamino-spezifischen Angaben von den allgemeinenen Angaben (Namespace xs). Technologie Memo Arno Schmidhauser 4 Tamino XML-Datenbank 5 Kommunikation mit Tamino Der Datenbank-Server in Tamino heisst X-Machine. Grundsätzlich gibt es zwei Möglichkeiten mit der X-Machine zu kommunizieren: a) über eine sehr enge, einfache URL/HTTP-Schnittstelle via Apache Server. b) über Programmiersprachen-Interfaces wie DOM für Java oder C# etc. Aus Sicht der X-Machine sind beide gleich und führen letzlich über das taminospezifsche Protokoll XTS. Aus Sicht des Datenbank-Clients sind sie aber verschieden. Any Client Type Java, C, C# Clients URL/HTTP calls with XMachine commands Java, C, C# Libraries e.g. DOM Interface Apache X-Modul Tamino Protocol (XTS over TCP/IP) X-Modul Tamino Protocol (XTS over TCP/IP) X-Machine Die Kommunikation via URL/HTTP sei an folgendem Beispiel illustriert, welches die Abfrage input()/book/title an die Datenbank schickt: http://host/tamino/mydb/mycollection?_xquery=input%28%29%2Fboo k%2ftitle Die so genannten X-Machine Commands (im Beispiel fettgedruckt) sind URL-Parameter, welche alle mit einem '_' beginnen. Weitere Beispiele sind _process, _delete zum Einfügen respektive Löschen von Dokumenten. Auf diesem Weg können auch Sessions erzeugt, Transaktionen bestätigt oder zurückgefahren werden, Administrationsbefehle abgesetzt werden usw. Ohne weiter Angabe läuft obiges Beispiel "sessionless" ab. Jede Anfrage an die Datenbank wird in diesem Fall automatisch bestätigt (committed). Sobald aber als Parameter _connect=* spezifiziert wird, startet der Tamino-Server eine Session, die bis zum expliziten Beendigungsbefehl mit _disconnect weiterläuft. Der _connect-Befehl liefert in Form eines HTTPHeaders eine Session ID und einen Session Key zurück. Diese beiden müssen bei jedem nachfolgenden Aufruf wieder mitgegeben werden. Die Session ID identifiziert die laufende Session, der Session Key ist lediglich eine fortlaufende Nummer für den jeweils nächsten Aufruf. Die beiden Pa- Technologie Memo Arno Schmidhauser 5 Tamino XML-Datenbank rameter müssen als URL-Parameter _sessionid und _sessionkey mitgegeben werden. 6 Abfragesprachen 6.1 XPath, XQuery XQuery ist die Hauptausrichtung in den neuen Version von Tamino (Genauer Produktname XQuery 4) Daneben wird ein Dialekt von XPath mit dem schwer zu unterscheidenden Produktname X-Query angeboten. Der Ausgangspunkt für eine XPath- oder XQuery-Abfrage, beispielsweise /book/title, ist eine Collection von XML-Dokumenten ( '/' ) . Das Eintrittskonstrukt in die Datenbank bei einer Abfrage ist daher meist input()/ oder collection( 'mycollection' )/ . Im ersten Fall wird die bei der Verbindung angegebene Collection verwendet, im zweiten Fall eine explizit genannte Collection. Abfragen können über mehrere Collections hinweg durchgeführt werden, eine Abfrageoptimierung findet jedoch nur innerhalb der Collection statt. 6.2 XUpdate Um XML-Daten auch über die Abfragesprache ändern zu können, hat Tamino eine spezielle Erweiterung von XQuery geschaffen. Diese ist im Moment zwar noch proprietär, wird aber mit grosser Wahrscheinlichkeit einen entsprechenden Entwurf des W3C wesentlich beeinflussen. Beispiele von Update-Befehlen: update for $b in input()/book where $b/title = "didle dum dum" do insert <subtitle>a introduction</subtitle> into $b/title update for $b in input()/book where $b/title = "didle dum dum" do insert <subtitle>a introduction</subtitle> following $b/title update for $b in input()/book where $b/title = "didle dum dum" do replace $b/title/text() with "Learning XML" update for $b in input()/book do delete $b/subtitle Technologie Memo Arno Schmidhauser 6 Tamino XML-Datenbank 6.3 Trigger Tamino unterstützt Trigger. Beim Einfügen, Ändern, Löschen eines Dokumentes wird eine programmierte Funktion aufgerufen (Server Extension, in Java, C# und weitere). 7 Indexe Die Bereitstellung von indexierten Daten ist unabdingbar für eine Datenbank. Tamino hat ein gut ausgebautes Indexsystem, um auch komplizierte Abfragen in grossen Collections mit guter Performance durchzuführen. Folgende Index-Grundarten kommen zum Einsatz: Standard-Index. Eingang: Textwert eines Knotens. Ausgang: Zugehörige Dokument-Referenz(en). Struktur: Baumartig, z.B. B*. Nutzen: Abfragen, wie /book/title[.= 'Learning XML'] werden beschleunigt. Der Index wird auf einen bestimmten Knotentyp gesetzt, und dessen Inhalt wird dann indexiert. Das Resultat der Indexsuche ist aber der Dokumentknoten, in dem sich der gesuchte Inhalt befindet. Falls der Index auf einen Knoten gesetzt wird, der weitere Kind-Knoten enthält, wird der gesamte Knoten atomisiert vor der Indexierung. Text-Index. Eingang: Wort oder Wortpattern innerhalb des Textwertes eines Knotens. Ausgang: Zugehörige Dokument-Referen(en). Struktur: Baumartig, z.B. B*. Nutzen: Abfragen, wie for $b in $input()/book where contains($b/title, 'Learning') return $b. Ein Text-Index teilt Knoteninhalte in Worte und Wortfragmente auf. Der DatenbankAdministrator kann die Indexierung stark beeinflussen: Positive und negative Wortliste, Fragment-Indexierung, Wortstamm-Indexierung. Ansonsten ähnlich dem Standard-Index. Multipath-Index. Eingang: Textwert eines Knotens. Ausgang: Eine Menge von Knotensequenzen, welche jede eine rückwärts verkettete Liste vom End-Knoten der Suche bis zum Dokument-Wurzelknoten darstellt. Nutzen: Abfragen mit Wildcards im Pfadausdruck werden wesentlich beschleunigt, zum Beispiel /book//title, oder /*/*/title. Es sind sowohl Standard-Multipath- wie Text-Multipath-Indexe möglich. Ein Referenz-Index ist eine Verfeinerung des Standard-Index, in dem irgend ein Knoten (nicht nur das Dokument) als Referenzknoten definiert werden kann, und unterhalb des Referenzknotens mehrere Pfade indexiert werden dürfen. Beispielsweise könnte der Referenzknoten /book/author sein. Die zu indexierenden Pfade könnten author/firstname und author/lastname sein. Damit wäre eine Abfrage der Art /book/author[ firstname='Steven' and lastname = 'Holzner'] extrem schnell, weil nur Autoren-Elemente auszugeben sind, und Bedingungen auf den zwei indexierten Unterpfaden gesetzt sind. Es sind sowohl Standard-Referenz- wie Text-Referenz-Indexe möglich. Struktur-Index. Eingang: Elementname. Ausgang: Zugehörige Dokument-Referen(en). Nutzen: Dokumentsammlungen mit sehr offenem Technologie Memo Arno Schmidhauser 7 Tamino XML-Datenbank Schema, so dass bereits der Elementname in einer Abfrage eine relevante Einschränkung der Ergebnismenger darstellt. Indexierung ist nur möglich, wenn ein Schema für die zu indexierenden Dokument definiert ist. 8 Transaktionsverhalten Bezüglich Concurrency Control bietet Tamino 5 Isolationsgrade: uncommittedDocument (entsprechend READ UNCOMMITTED bei SQL), committedCommand (entsprechend READ COMMITTED bei SQL), stableDocument (entsprechend REPEATABLE READ bei SQL) und serializable. 9 Entwicklungs-Tools Der X-Plorer ermöglicht die interaktive Bedienung, Durchforstung und Pflege der Datenbank. Einige Interfaces sind auch als HTML-Seiten verfügbar und bedürfen damit keiner Installation. Ein Schema Editor ermöglicht die Definition eines oder mehrere XML Schema, dem die einzufügenden XML-Dokumente genügen müssen. Mit dem Tamino Manager können Datenbanken und Benutzer angelegt, Server-Parameter eingestellt, aktive Sessions und Transaktionen überwacht und viele Management-Aufgaben durchgeführt werden. Der Tamino-Manager ist webbasiert. 10 Verschiedenes Ist Schema Evolution unterstützt? Ja. Das neue Schema sollte so sein, dass bestehende Dokument nicht ungültig werden. Der Benutzer ist für die Validierung der bestehenden Dokumente gegen das neue Schema verantwortlich. Gibt es eine Art Primärschlüssel? Ja. Jedes Dokument bekommt per default ein internes Attribut ino:id mit. Dieses ist mit der Funktion tf:getInoId() abrufbar. Dieser sollte allerdings nur für kurzfristige Programmatische Zwecke verwendet werden, wie das Lesen in eine Applikation und Zurückschreiben auf die Datenbank. Für permanente Beziehungen zwischen Dokumenten wird mit Vorteil ein eigener Primärschlüssel definiert. Technologie Memo Arno Schmidhauser 8 -----------------------------------------------------------------------------------------------------------*/ import java.io.*; import java.net.*; import java.util.*; import javax.xml.xpath.*; import javax.xml.parsers.*; import javax.xml.transform.*; import javax.xml.transform.dom.*; 11.4.2005 Arno Schmidhauser History <student id="1"> <name>Hans Besserwisser</name> <klasse>ead01</klasse> <faecher> <fach> <titel>Java für Profis</titel> <ects>2</ects> </fach> ... </faecher> </student> This program relies on a student document with the following structure in the tamino database. Example documents can be added with http://swsdb.hta-be.bfh.ch/TaminoXQuery.html This program does the following steps: 1) send a query to the tamino database to retrieve all students who belong to a "klasse". 2) add a <fach>...</fach> entry to each student document 3) write back the student documents to the database /* -------------------------------------------------------------------------------------------------------- 11 Beispiel HTTP-Anbindung Technologie Memo } Arno Schmidhauser 10 // get session from database String queryURL = collectionUrl + "?_connect=*&_isolationLevel=serializable"; URLConnection uc = (new URL( queryURL )).openConnection(); sessionid = uc.getHeaderField( "X-INO-Sessionid" ); sessionkey = uc.getHeaderField( "X-INO-Sessionkey" ); // create transformer for transforming DOM tree with XSL stylsheet TransformerFactory trafactory = TransformerFactory.newInstance(); transformer = trafactory.newTransformer(); transformer.setOutputProperty( "omit-xml-declaration", "yes" ); DocumentBuilderFactory docfactory = DocumentBuilderFactory.newInstance(); docfactory.setNamespaceAware( true ); builder = docfactory.newDocumentBuilder(); /** * Constructor. */ public TaminoDomDocumentManager( String collectionUrl ) throws Exception { this.collectionUrl = collectionUrl; /** * TaminoDocumentManager retrieves student documents from database, edits them, * and writes them back to database. */ public class TaminoDomDocumentManager { protected String collectionUrl; protected String sessionid; protected String sessionkey; protected DocumentBuilder builder; protected Transformer transformer; protected static String urlEncoding = "iso-8859-1"; // since no http encoding header is sent, tamino-apache // is expecting iso-8859-1 by default. import javax.xml.transform.stream.*; import org.w3c.dom.*; Tamino XML-Datenbank Technologie Memo } Arno Schmidhauser // send Query Document doc = sendQuery( updQuery ); commit(); return doc; 11 updQuery = updQuery.replaceAll( "\\$param1", serializeDOM( student ) ); // prepare update query String updQuery = " update " + " let $p := $param1 " + " for $s in input()/student " + " where $s/@id = $p/@id " + " do replace $s with $p "; /** * save student record back to database */ protected Document saveStudent( Element student ) throws Exception { } // send Query Document doc = sendQuery( getQuery ); commit(); return doc; /** * retrieve studentlist from database */ protected Document getStudents( String klasse ) throws Exception { // prepare query to retrieve student String getQuery = " for $s in input()/student " + " where $s/klasse = '$param1' " + " return $s "; getQuery = getQuery.replaceAll( "\\$param1", klasse ); Tamino XML-Datenbank Technologie Memo Arno Schmidhauser /** * disconnect session */ protected Document disconnect() throws Exception { // compose disconnect url String disconnectUrl = collectionUrl + "?" + "_sessionid=" + sessionid + "&" + "_sessionkey=" + sessionkey + "&" + "_disconnect=*"; /** * commit transaction */ protected Document commit() throws Exception { // compose commit url String commitUrl = collectionUrl + "?" + "_sessionid=" + sessionid + "&" + "_sessionkey=" + sessionkey + "&" + "_commit=*"; // send request return sendUrlRequest( commitUrl ); } 12 /** * send XQuery and wrap result into DOM document */ protected Document sendQuery( String query ) throws Exception { // open url connection to tamino database and execute query String queryUrl = collectionUrl + "?" + "_sessionid=" + sessionid + "&" + "_sessionkey=" + sessionkey + "&" + "_xquery=" + URLEncoder.encode( query, urlEncoding ); return sendUrlRequest( queryUrl ); } Tamino XML-Datenbank Technologie Memo Arno Schmidhauser /** * get next id value. database must contain a document named 'counter' /** * serialize DOM tree to string */ protected String serializeDOM( Node n ) throws Exception { try { // write DOM tree to string DOMSource source = new DOMSource( n ); ByteArrayOutputStream bos = new ByteArrayOutputStream(); StreamResult result = new StreamResult( bos ); transformer.transform( source, result ); return bos.toString( "utf-8" ); } catch( Exception e ) { return "<serializationError/>"; } } } // parse input stream to DOM document Document doc = builder.parse( is ); is.close(); return doc; /** * sendUrl */ protected Document sendUrlRequest( String urlReq ) throws Exception { URLConnection uc = (new URL( urlReq )).openConnection(); sessionkey = uc.getHeaderField( "X-INO-Sessionkey" ); InputStream is = uc.getInputStream(); } // send request return sendUrlRequest( disconnectUrl ); Tamino XML-Datenbank 13 Technologie Memo Arno Schmidhauser // get students from database Document doc = docman.getStudents( klasseArg ); System.out.println( "students retrieved." ); 14 /** * main */ public static void main( String argv[] ) { if ( argv.length != 4 ) { System.out.println( "Usage: TaminoDomDocumentManager <collectionUrl> <klasse> <fachTitel> <ectsPkte> " ); System.out.println( "Example: TaminoDomDocumentManager http://swspc069/tamino/swsdb/swspublic ead01 datenbanken 5 " ); System.exit( 1 ); } try { String collectionUrl = argv[0]; String klasseArg = argv[1]; String fachArg = argv[2]; String punkteArg = argv[3]; TaminoDomDocumentManager docman = new TaminoDomDocumentManager( collectionUrl ); } Document confirmation = sendQuery( incQuery ); Document doc = sendQuery( getQuery ); String cVal = doc.getElementsByTagName( "counter" ).item(0).getFirstChild().getNodeValue(); System.out.println( cVal ); return cVal; String getQuery = " input()/counter"; * which contains the current id value e.g.: <counter>1000</counter> * this function is currently not used in the main program. */ protected String getNextId() throws Exception { String incQuery = " update " + " let $c := input()/counter/text() " + " do replace $c with ( $c + 1 ) "; Tamino XML-Datenbank } Technologie Memo Arno Schmidhauser /* * Copyright (c) 2002-2004 SOFTWARE AG, All Rights Reserved. */ 12 Beispiel DOM-Anbindung } } catch ( Exception e ) { e.printStackTrace(); } } docman.disconnect(); // save student to database Document confirmation = docman.saveStudent( student ); System.out.println( "student updated." ); 15 // modify student record: add new course and ects points. // instead of this code a generic graphical xml editor might be called Element faecher = (Element)(student.getElementsByTagName( "faecher" ).item(0)); Element fach = doc.createElement( "fach" ); faecher.appendChild( fach ); Element titel = doc.createElement( "titel" ); fach.appendChild( titel ); titel.appendChild( doc.createTextNode( fachArg ) ); Element ects = doc.createElement( "ects" ); fach.appendChild( ects ); ects.appendChild( doc.createTextNode( punkteArg ) ); // add course record for each student for( int i = 0; i < studList.getLength(); i++ ) { Element student = (Element)studList.item(i); NodeList studList = doc.getElementsByTagName( "student" ); Tamino XML-Datenbank Arno Schmidhauser com.softwareag.tamino.db.api.accessor.TAccessLocation; com.softwareag.tamino.db.api.accessor.TAccessorException; com.softwareag.tamino.db.api.accessor.TDeleteException; com.softwareag.tamino.db.api.accessor.TInsertException; com.softwareag.tamino.db.api.accessor.TQuery; com.softwareag.tamino.db.api.accessor.TQueryException; com.softwareag.tamino.db.api.accessor.TSystemAccessor; com.softwareag.tamino.db.api.accessor.TXMLObjectAccessor; com.softwareag.tamino.db.api.common.TAccessFailureMessage; com.softwareag.tamino.db.api.common.TException; com.softwareag.tamino.db.api.connection.TConnection; com.softwareag.tamino.db.api.connection.TConnectionFactory; com.softwareag.tamino.db.api.connection.TLockMode; Technologie Memo import import import import import import import import import import import import import 16 /* || Example for the Tamino API for Java. || || Assumes that there is a Tamino database called "mydb". || The example simply uses the default collection ino:etc. || This collection should only be used for examples/test code. || It shouldn't generally be used for real applications. || || The example does the following: || || establishes a connection to the Tamino database || obtains a system accessor and prints out some system information || obtains an XML accessor || reads some XML documents from files and inserts them into the collection ino:etc || creates two queries, one for all person documents and one for all persons named "Atkins" || queries all persons and list them || use a boolean query to check if any person named "Atkins" is stored in the database || if such persons are found, delete them || queries again all persons and list them || delete the rest of the persons || closes the connection */ package com.softwareag.tamino.db.api.examples.person; Tamino XML-Datenbank com.softwareag.tamino.db.api.connection.TLocalTransaction; com.softwareag.tamino.db.api.io.TStreamWriteException; com.softwareag.tamino.db.api.objectModel.TXMLObject; com.softwareag.tamino.db.api.objectModel.TXMLObjectIterator; com.softwareag.tamino.db.api.objectModel.TXMLObjectModel; com.softwareag.tamino.db.api.objectModel.dom4j.TDOM4JObjectModel; com.softwareag.tamino.db.api.response.TResponse; java.io.FileNotFoundException; java.io.InputStream; java.util.List; org.dom4j.Element; Technologie Memo Arno Schmidhauser 17 // Helpermethod to get the text of a given tagname from a DOM4J tree private static String getDOM4JElementTextByTagName(Element element, String tagname) { List list = element.elements( tagname ); Element elem = (Element)list.get(0); return elem.node(0).getStringValue(); } } if (!systemaccessor.isServerAlive()) { return false; } else { System.out.println( " server is alive" ); System.out.println( "\nHere is some systeminformation" ); System.out.println( "------------------------------\n" ); System.out.println( "The Tamino server hosting " + DATABASE_URI + " is version " + systemaccessor.getServerVersion() ); System.out.println( "(Server API version: " + systemaccessor.getAPIVersion() + ", Tamino API for Java version: " + systemaccessor.getAPIVersion() + ")\n" ); return true; } // use a sytem accessor, to check, if the database is alive and print some system information to stdout protected static boolean checkServerAndPrintSystemInformation(TConnection connection) throws TAccessorException { // Obtain the TSystemAccesor TSystemAccessor systemaccessor = connection.newSystemAccessor(); public class ProcessPersonsDOM4J { import import import import import import import import import import import Tamino XML-Datenbank Technologie Memo Arno Schmidhauser 18 } catch (TInsertException insertException) { System.out.print( "\nCan't insert: " ); printPerson( xmlObject ); System.out.println( " Reason: " + insertException.getAccessFailureException().getMessageLine() + "\n" ); } return xmlObject; System.out.print( " Inserted: " ); printPerson(xmlObject); try { // Invoke the insert operation and obtain the response. TResponse response = accessor.insert( xmlObject ); // Read a document out of the classpath and insert it into the database. InputStream myInputStream = (new ProcessPersonsDOM4J()).getClass().getResourceAsStream( filename ); xmlObject.readFrom( myInputStream ); // read a given filename into an TXMLObject, store it in the database and print the person protected static TXMLObject performInsertPersonFromFile(TXMLObjectAccessor accessor, String filename) throws TException, FileNotFoundException { // Instantiate an empty TXMLObject instance related to the DOM4J object model. TXMLObject xmlObject = TXMLObject.newInstance( TDOM4JObjectModel.getInstance() ); } System.out.print( " (" ); System.out.print( "ino:id=\"" + xmlObject.getId() +"\" " ); System.out.print( "collection=\"" + xmlObject.getCollection() +"\" " ); System.out.print( "doctype=\"" + xmlObject.getDoctype() +"\" " ); System.out.println( ")" ); String surname = getDOM4JElementTextByTagName(e, "surname"); String firstname= getDOM4JElementTextByTagName(e, "firstname"); System.out.print( surname + ", " + firstname); // Obtain the DOM4J root element Element e = (Element)xmlObject.getElement(); // List some data about a person to stdout private static void printPerson(TXMLObject xmlObject) throws TStreamWriteException { Tamino XML-Datenbank { Technologie Memo Arno Schmidhauser 19 // delete all documents for a given query with a given accessor protected static void performDelete(TXMLObjectAccessor accessor, TQuery query) throws TException { // perform a query and list all persons, which are returned protected static void performQueryAndListPersons(TXMLObjectAccessor accessor, TQuery query) throws TException // Now lets make the query try { TResponse response = accessor.query( query ); TXMLObjectIterator iterator = response.getXMLObjectIterator(); System.out.print( "The query \"" + query + "\" returns " ); if (!iterator.hasNext()) { System.out.println( "no documents!" ); } else { System.out.println( performCountQuery( accessor, query ) + " documents, which are:" ); while (iterator.hasNext()) { TXMLObject xmlObject = iterator.next(); System.out.print( " " ); printPerson(xmlObject); } } } catch (TQueryException queryException) { showAccessFailure( queryException ); throw queryException; } } // take a given query, put the count() function around and return the result as String private static String performCountQuery(TXMLObjectAccessor accessor, TQuery query) throws TException try { // Build a new query string TQuery countquery = TQuery.newInstance( "count(" + query.getExpression() + ")" ); return accessor.query( countquery ).getQueryContentAsString(); } catch (TQueryException queryException) { showAccessFailure( queryException ); throw queryException; } } } Tamino XML-Datenbank { Technologie Memo Arno Schmidhauser // Instantiate the specific TDOM4JObjectModel TXMLObjectModel dom4jObjectModel = TDOM4JObjectModel.getInstance(); 20 // Obtain the connection factory TConnectionFactory connectionFactory = TConnectionFactory.getInstance(); // Obtain the connection to the database TConnection connection = connectionFactory.newConnection( DATABASE_URI ); TLocalTransaction myTransaction=connection.useLocalTransactionMode(); connection.setLockMode(TLockMode.SHARED); // Check if the connection is available and print out some system information if ( !checkServerAndPrintSystemInformation( connection ) ) return; public static void main(String[] args) throws TException { //TTrace.setActiveTrace(true); // Print out a program header to stdout System.out.println( "\nProcessPersonsDOM4J sample programm" ); System.out.println( "==============================" ); System.out.print( "Connecting to Tamino database " + DATABASE_URI + ", ..." ); // Show the reason for the access failure. private static void showAccessFailure(TAccessorException accessorException) { // Obtain an access failure message telling the exact reason if Tamino request failed. TAccessFailureMessage accessFailure = accessorException.getAccessFailureException(); if ( accessFailure != null ) System.out.println( "Access failed with:" + accessFailure ); else System.out.println( "Access failed:" + accessorException.getMessage() ); } } // Finally, lets delete the document again try { TResponse response = accessor.delete( query ); System.out.println("\nDeleted all documents for query \"" + query + "\""); } catch (TDeleteException deleteException) { showAccessFailure( deleteException ); throw deleteException; } Tamino XML-Datenbank Technologie Memo Arno Schmidhauser // Do some processing, if persons named "Atkins" are stored 21 // Create a boolean query and check if persons named "Atkins" are stored TQuery queryAtkins = TQuery.newInstance( "//surname='Atkins'" ); String queryAtkinsResult = accessor.query( queryAtkins ).getQueryContentAsString(); System.out.println( "\nThe query \"" + queryAtkins + "\" returns \"" + queryAtkinsResult + "\"" ); boolean AtkinsAvailable = new Boolean( queryAtkinsResult ).booleanValue(); System.out.println(""); // Initiate a query to count and list all instances of a certain Doctype performQueryAndListPersons( accessor, queryall ); // Build a query to reference documents of doctype "person" with surname = "Atkins" TQuery querysome = TQuery.newInstance( xmlObject.getDoctype() + "[//surname='Atkins']" ); // Build a query to reference all documents of doctype "person" TQuery queryall = TQuery.newInstance( xmlObject.getDoctype() ); performInsertPersonFromFile( accessor, "person1.xml" ); performInsertPersonFromFile( accessor, "person2.xml" ); performInsertPersonFromFile( accessor, "person3.xml" ); performInsertPersonFromFile( accessor, "person4.xml" ); xmlObject = performInsertPersonFromFile( accessor, "person5.xml" ); // read person documents from files and insert them into the "people" collection System.out.println( "Reading documents from file and insert into database\n" ); try { // Instantiate an empty TXMLObject instance related to the DOM4J object model. TXMLObject xmlObject = TXMLObject.newInstance( TDOM4JObjectModel.getInstance() ); // Print header for database operations System.out.println( "Insert and query and delete in default collection \"ino:etc\"" ); System.out.println( "-----------------------------------------------------------\n" ); // Do the object model registration. TXMLObjectModel.register( dom4jObjectModel ); // Obtain a TXMLObjectAccessor to the "ino:etc" collection with an underyling DOM4J object model TXMLObjectAccessor accessor = connection.newXMLObjectAccessor( TAccessLocation.newInstance( "ino:etc" ) , dom4jObjectModel ); Tamino XML-Datenbank Technologie Memo } Arno Schmidhauser 22 // Constant for the database URI. Please edit to use your uri of interest. private final static String DATABASE_URI = "http://localhost/tamino/mydb"; } } catch (TException taminoException) { if (myTransaction != null) myTransaction.rollback(); taminoException.printStackTrace(); } catch (FileNotFoundException filenotfoundException) { filenotfoundException.printStackTrace(); } finally { // Close the connection. connection.close(); } // Initiate the removal performDelete( accessor, queryall ); } System.out.println(""); // Initiate a query to count and list all instances of a certain Doctype performQueryAndListPersons( accessor, queryall ); myTransaction.commit(); // Initiate the removal of all "Atkins" performDelete( accessor, querysome ); if (AtkinsAvailable) { System.out.println("So list and then delete all \"Atkins\" documents\n"); // Initiate a query to count and list some instances of a certain Doctype performQueryAndListPersons( accessor, querysome); Tamino XML-Datenbank