SQL, PHP, XML, XSL

Roger Fischer

Christian Stocker


Inhaltsverzeichnis

Die Tools
Von der Datenbank-Tabelle project zur XML-Datei project.xml
Behind the Scene: Die sql2xml Klasse
Von der Datenbanktabelle project zu zerostyle.html
Behind the Scene: XSL Transformieren mit PHP
Von der Datenbanktabelle project zu slashdot.html
Von der Datenbanktabelle project zu sql2pdf.pdf
Behind the Scene: PHP und Java
Ausblick und Diskussion

Anmerkung

Dieser Artikel wurde mit Docbook geschrieben. Das XML-File findet man hier.

Wenn Ihnen dieser Artikel und die PHP-Klassen bei Ihren eigenen Projekten geholfen haben, würden wir uns über Ihr Feedback freuen.

Zusammenfassung

Im folgenden Artikel stellen wir die Tools vor, die wir zur Transformierung von Daten zu XML und später zu HTML, PDF verwenden.

Als erstes zeigen wir wie man vom Inhalt einer MySQL-Datenbanktabelle zu einer XML-Datei kommt.

Von da aus transformieren wir diese XML-Datei mit XSL in zwei verschiedene HTML-Dateien und eine PDF-Datei. Dabei versuchen wir auch einige XSLT und XSL-FO Konstrukte näher zu erklären.

Das Ganze wird durch die Interactive Broadcast Application-PHP Klassen, kurz bitflux-PHP Klassen, ermöglicht, die wir fortwährend erläutern.

Die Tools

  • LAMP = Linux, Apache, MySQL, PHP

  • PHP mit Sablotron von Ginger Alliance

  • DOM-XML

  • bitflux Classes

  • FOP von xml.apache.org zur Generierung von PDF's (Adobe)

Im Bezug auf XML und verwandte Technologien, verwenden wir

  • XML 1.0 selbst (Extensible Markup Language)

  • XSLT 1.0 (Extensible Stylesheet Language Transformations)

  • XSL-FO 1.0 (Extensible Stylesheet Language Formatting Objects)

Von der Datenbank-Tabelle project zur XML-Datei project.xml

Zuerst wollen wir die Datenbank bzw. Tabellen-Struktur vorstellen. Wir haben auf eine relationale Datenbank verzichtet, damit die weiterführenden Transformationen nicht zu schwer verständlich sind.

Hier eine Ansicht der Tabelle project aus der MySQL-Datenbank nomadweb, wie man sie auf phpMyAdmin, einem Webadministrationstool für MySQL, sehen würde:

Die Idee ist alle Felder der neuesten 5 Datensätze aus dieser Tabelle herauszuholen. Dazu verwenden wir das folgende SQL-Statement: SELECT * FROM project ORDER BY new DESC LIMIT 5. Mit Hilfe der PHP-Klasse sql2xml und der PEAR-DB-Klasse machen wir daraus die XML-Datei project.xml. Näheres zu PEAR und sql2xml folgt unter Behind the Scene: Die sql2xml Klasse.

Hier nun das PHP Skript, dass die Datenbank abfragt und diese Abfrage in einen XML-String umwandelt und dann in die Datei project.xml schreibt.

 
		<?php
		// +----------------------------------------------------------------------+
		// | bitflux CMS                                             |
		// +----------------------------------------------------------------------+
		// | Copyright (c) 2001 bitflux GmbH                        |
		// +----------------------------------------------------------------------+
		// | If you did not receive a copy of the GPL license and are unable to   |
		// | obtain it through the world-wide-web, please send a note to          |
		// | license@bitflux.ch so we can mail you a copy immediately.              |
		// +----------------------------------------------------------------------+
		// | Authors: bitflux classes by Christian Stocker <chregu@bitflux.ch>          |
		// |          Roger Fischer <roger@bitflux.ch>                              |
		// +----------------------------------------------------------------------+
		//
		//
		
		/**
		* This file queries the table "project" of the Nomadweb database.      
		*
		* The table "project" has the following fields:                        
		* ID, author, email, date, title_de, title_en, subtitle_de,            
		* subtitle_en, text_short_de, text_short_en, text_long_de,             
		* text_long_en, file_de, file_en, url, thumbnail, image, mediatype_ID, 
		* media_file, active, highlight, changed, new, subsection_ID           
		*                                                                      
		* It uses the Pear DB classes, the bitflux sql2xml class as well as the    
		* bitflux debug functions. The out put is a xml-file.                                                
		**/                                                                    


		include_once ("DB.php");
		include_once ("XML/sql2xml.php");
		include_once ("functions/debug.php");

		//instantiate the xml_sql2xml object
		$xml = new xml_sql2xml;    

		//connect to the database the pearway                            
		$db = DB::connect("mysql://root@localhost/nomadweb"); 

		//make your query, the newest one always comes on top, not more then 5 are outputted
		$result = $db->query("SELECT * FROM project ORDER BY new DESC LIMIT 5");        

		$xmlstring = $xml->getxml($result);

		//write the result string to a xml-file
		$fp = fopen("project.xml", "w+");
		fwrite($fp,$xmlstring);
		fclose($fp);
		
		debug::print_xml($xmlstring);
   	?>
		  

Behind the Scene: Die sql2xml Klasse

Hier gehts zum Tutorial der sql2xml Klasse. Dort sollte alles relevante über diese Klasse stehen, inkl. Link zum herunterladen (in english)

Von der Datenbanktabelle project zu zerostyle.html

Hier zuerst die einzelnen Dateien. project.xml kennen wir ja bereits von vorher. Natürlich wird diese Datei jedes Mal dynamisch aus der Datenbank generiert. Neu sind zerostyle.xsl sowie das Phpskript sql2html_zerostyle.php.

Schauen wir uns vielleicht zuerst das Phpskript sql2html_zerostyle.php an:

		<?php
		// +----------------------------------------------------------------------+
		// | bitflux CMS                                             |
		// +----------------------------------------------------------------------+
		// | Copyright (c) 2001 bitflux GmbH                        |
		// +----------------------------------------------------------------------+
		// | If you did not receive a copy of the GPL license and are unable to   |
		// | obtain it through the world-wide-web, please send a note to          |
		// | license@bitflux.ch so we can mail you a copy immediately.              |
		// +----------------------------------------------------------------------+
		// | Authors: bitflux classes by Christian Stocker <chregu@bitflux.ch>          |
		// |          Roger Fischer <roger@bitflux.ch>                              |
		// +----------------------------------------------------------------------+
		//

		/**
		* This file queries the table "project" of the Nomadweb database.    
		*                                                                      
		* The table "project" has the following fields:                        
		* ID, author, email, date, title_de, title_en, subtitle_de,            
		* subtitle_en, text_short_de, text_short_en, text_long_de,            
		* text_long_en, file_de, file_en, url, thumbnail, image, mediatype_ID, 
		* media_file, active, highlight, changed, new, subsection_ID          
		*                                                         
		* It uses the Pear DB classes, the bitflux sql2xml class as well as the   
		* bitflux debug functions. It also uses the processor class.              
		**/


		include_once ("xsl/processor.php");
		include_once ("DB.php");
		include_once ("XML/sql2xml.php");
		include_once ("functions/debug.php");

		//instantiate the xml_sql2xml object
		$xml = new xml_sql2xml;    

		//connect to the database the pearway                            
		$db = DB::connect("mysql://root@localhost/nomadweb"); 

		//make your query, the newest one always comes on top, not more then 5 are outputted
		$result = $db->query("SELECT * FROM project ORDER BY new DESC LIMIT 5");        

		//html-translation - <p></p> tag is recognized and transformed 
		$xmlstring = common::html_translation($xml->getxml($result,$options));
		
		//make html out of xml and xsl
		$html= new xsl_processor;
		$xslstring = common::read_file("zerostyle.xsl");
		$newhtml = $html->get_html_from_string ($xmlstring,$xslstring);

		//write the result string to a html-file
		$fp = fopen("zerostyle.html", "w+");
		fwrite($fp,$newhtml);
		fclose($fp);

		debug::print_xml($newhtml);

		?>
	
	

Nur der untere Teil des Skripts ist neu im Vergleich zum Skript, dass wir bereits kennen. Hier nun wird der xmlstring (der project.xml entspricht) mit dem xslstring von zerostyle.xsl prozessiert. Am Ende haben wir dann zerostyle.html.

Bevor wir zerostyle.xsl näher betrachten, studieren wir project.xml etwas genauer. Dies wird mit folgender Darstellung, die einen kleinen Teil von project.xml zeigt, vielleicht etwas klarer:

Ein XML-Dokument ist wie ein Baum, der aus Knoten, sogenannten Nodes besteht. Diese Nodes können wir mit XPath identifizieren.

Schauen wir uns jetzt zerostyle.xsl an. Dabei interessieren wir uns besonders für folgende Konstrukte:

  • <xsl:output method="html"/>

  • <xsl:template match="result"/>

  • <xsl:apply-templates select="row"/>

  • <xsl:value-of select="title_de"/>

  • <xsl:apply-templates select="row" mode="toc"/>

Behind the Scene: XSL Transformieren mit PHP

Wie geht das nun genau mit dem XML + XSL = HTML in PHP?

Es gibt 2 Möglichkeiten den Sablotron-Prozessor aufzurufen in PHP.

  • Die XML- und XSL-Dateien liegen als Dateien auf dem lokalen Filesystem. (xslt_run())

  • Die XML- und XSL-Daten sind in einem String abgelegt (xslt_process())

Fü unser Beispiel brauchen wir die 2. Funktion, da wir die XML-Daten dynamisch generieren und nicht jedesmal dafür eine Datei schreiben wollen (Performancemässig wäre das nicht ideal). Ein Nachteil von xslt_process ist jedoch, dass damit zur Zeit keine Parameter an die XSL-Transformation übergeben werden können. Das soll aber in diesem Beispiel nicht weiter stören.

        //initialize XML_sql2xml class
        
        $xml = new XML_sql2xml("mysql://root@localhost/nomadweb");    
        
        //lies xsl-file in $xslstring
        
        $fd = fopen( $file, "r" );
        $xslstring = fread( $fd, filesize( $file ) );
        fclose( $fd );

        //hol die xml daten mithilfe der XML_sql2xml klasse und speicher sie in $xmlstring
        
        $xmlstring = $xml->getxml("SELECT * FROM project ORDER BY new DESC LIMIT 5");
        
        //Hier passiert die eigentliche Transformation.
        //Die beiden Strings $xslstring und $xmlstring werden an den sablotron prozessor übergeben
        //Das Resultat wird in die Variable $result als String abgelegt.
        
        $msg = xslt_process($xslstring, $xmlstring, $result);
        
        //Fehler-testen und ausgeben. xslt_process gibt False aus, wenn etwas schief ging.
        
        if(! ($msg)) {
            print ("Transformation failed.");
            print xslt_error();
        }
        
        //resultat an den browser schicken. Hier könnte man natürlich noch weiteres mit
        // dem String tun. Zum Beispiel in einem User-Land-Cache speichern, etc.
        
        print $result;
	

Die komplette Funktionsliste zur XSLT-Transformation kann unter http://www.php.net/manual/en/ref.xslt.php angesehen werden.

Von der Datenbanktabelle project zu slashdot.html

Hier wieder die einzelnen Dateien. project.xml kennen wir ja bereits von vorher. Neu sind slashdot.xsl sowie das Phpskript sql2html_slashdot.php.

Schauen wir uns wieder zuerst das Phpskript sql2html_slashdot.php an:

		<?php
		// +----------------------------------------------------------------------+
		// | bitflux CMS                                             |
		// +----------------------------------------------------------------------+
		// | Copyright (c) 2001 bitflux GmbH                        |
		// +----------------------------------------------------------------------+
		// | If you did not receive a copy of the GPL license and are unable to   |
		// | obtain it through the world-wide-web, please send a note to          |
		// | license@bitflux.ch so we can mail you a copy immediately.              |
		// +----------------------------------------------------------------------+
		// | Authors: bitflux classes by Christian Stocker <chregu@bitflux.ch>          |
		// |          Roger Fischer <roger@bitflux.ch>                              |
		// +----------------------------------------------------------------------+
		//

		/**
		* This file queries the table "project" of the Nomadweb database.     
		*                                                                     
		* The table "project" has the following fields:                        
		* ID, author, email, date, title_de, title_en, subtitle_de,            
		* subtitle_en, text_short_de, text_short_en, text_long_de,             
		* text_long_en, file_de, file_en, url, thumbnail, image, mediatype_ID, 
		* media_file, active, highlight, changed, new, subsection_ID           
		*                                                                     
		* It uses the Pear DB classes, the bitflux sql2xml class as well as the     
		* bitflux debug functions. It also uses the processor class.               
		**/                                                                   


		include_once ("xsl/processor.php");
		include_once ("DB.php");
		include_once ("XML/sql2xml.php");
		include_once ("functions/debug.php");

		//instantiate the xml_sql2xml object
		$xml = new xml_sql2xml;    

		//connect to the database the pearway                            
		$db = DB::connect("mysql://root@localhost/nomadweb"); 

		//make your query, the newest one always comes on top, not more then 5 are outputted
		$result = $db->query("SELECT * FROM project ORDER BY new DESC LIMIT 5");        

		//html-translation - <p></p> tag is recognized and transformed 
		$xmlstring = common::html_translation($xml->getxml($result,$options));
		
		//make html out of xml and xsl
		$html= new xsl_processor;
		$xslstring = common::read_file("slashdot.xsl");
		$newhtml = $html->get_html_from_string ($xmlstring,$xslstring);

		//write the result string to a html-file
		$fp = fopen("slashdot.html", "w+");
		fwrite($fp,$newhtml);
		fclose($fp);

		debug::print_xml($newhtml);

		?>
	
	

Schauen wir uns slashdot.xsl an. Dabei interessieren wir uns besonders für folgende Konstrukte:

  • <xsl:call-template name="slashdot"/>

  • <xsl:template name="slashdot"/>

  • <xsl:for-each select="//result/row"/>

Von der Datenbanktabelle project zu sql2pdf.pdf

Hier wieder die einzelnen Dateien. Neu sind xslt_xsl-fo.xsl sowie das Phpskript sql2pdf.php. Eigentlich müsste es noch so etwas wie xsl-fo.fo geben, da vorerst durch die Transformation mit XSLT erst eine fo-Datei entsteht. Erst diese wird dann z.B. mit FOP von Apache in ein PDF umgewandelt. Hier haben wir aber alles zusammengelegt. D.h. dass beim Aufruf des PHP-Skripts direkt ein PDF augegeben wird.

Schauen wir uns wieder zuerst das Phpskript sql2pdf.php an:

		<?php
		// +----------------------------------------------------------------------+
		// | bitflux CMS                                             |
		// +----------------------------------------------------------------------+
		// | Copyright (c) 2001 bitflux GmbH                        |
		// +----------------------------------------------------------------------+
		// | If you did not receive a copy of the GPL license and are unable to   |
		// | obtain it through the world-wide-web, please send a note to          |
		// | license@bitflux.ch so we can mail you a copy immediately.              |
		// +----------------------------------------------------------------------+
		// | Authors: bitflux classes by Christian Stocker <chregu@bitflux.ch>          |
		// |          Roger Fischer <roger@bitflux.ch>                              |
		// +----------------------------------------------------------------------+
		//

		/**
		* This file queries the table "project of the Nomadweb database.       
		* It then applies a xslt-stylesheet to the outputed xmlstring.        
		* The outcome is xsl-fo. Then it calls the fo2pdf class and the final  
		* outcome is a pdf-file. That's great, isn't it!                       
		*                                                                     
		* It uses the Pear DB classes and the bitflux sql2xml class as well as the 
		* bitflux debug functions, the xsl_processor class and the fo2pdf class.   
		**/                                                                      

		include_once ("XML/fo2pdf.php");
		include_once ("xsl/processor.php");
		include_once ("DB.php");
		include_once ("XML/sql2xml.php");
		include_once ("functions/debug.php");

		//instantiate the xml_sql2xml object
		$xml = new xml_sql2xml;    

		//connect to the database the pearway                            
		$db = DB::connect("mysql://root@localhost/nomadweb"); 

		//make your query
		$result = $db->query("SELECT * FROM project ORDER BY new DESC LIMIT 5");        

		//html-translation - <p></p> tag is recognized and transformed 
		$xmlstring = common::html_translation($xml->getxml($result,$options));

		//make xsl-fo with xml and xslt_xsl.fo stylesheet
		$xsl= new xsl_processor;
		$xslstring = common::read_file("xslt_xsl-fo.xsl");
		$newxsl = $xsl->get_html_from_string ($xmlstring,$xslstring);

		//write the resulting xsl.fo-document to a pdf
		$pdf = new XML_fo2pdf( );
		$pdf->runFromString($newxsl);
		$pdf->printPDF();
		$pdf->deletePDF();

		?>
	
	

Schauen wir uns nun xslt_xsl-fo.xsl etwas genauer an. Dabei interessieren wir uns besonders für folgende XSLT-Konstrukte mit dem Prefix xsl:

  • <xsl:for-each select="//row"/>

  • <xsl:sort select="author" data-type="text" lang="C"/>

Natürlich sind nun noch die XSL-FO-Konstrukte hinzugekommen. Sie tragen das Prefix fo. Hier nur zwei wichtige Konstrukte:

  • <fo:region-body column-count="2" reference-orientation="0" margin="20mm" />

  • <fo:block space-before="12pt" font-size="14pt" font-family="Helvetica" font-weight="bold"/>

Behind the Scene: PHP und Java

PHP kann auch direkt auf Javaklassen zugreifen. Dazu muss PHP mit der Option --with-java kompiliert werden und ein paar Einstellungen in php.ini müssen vorgenommen werden. Ist nicht wirklich trivial, aber das Tutorial unten gibt ein paar Tips.

Die Java-Anbindung von PHP nutzen wir in diesem Beispiel um den FOP-Prozessor von apache.org ansprechen zu können. Diesen gibt's nur als Java-Programm und das wird sich wohl auch nicht so schnell ändern.

Der Vorteil dieser Java-Anbindung in PHP ist, dass damit die ganze Welt von Java auch in PHP offen steht. Vor allem und gerade im XML-Bereich werden die meisten Anwendungen zuerst für Java veröffentlicht. Der Nachteil ist, dass das Ganze nicht wirklich schnell ist, da PHP bei jedesmal eine Java-Instanz öffnen muss. Mit entsprechenden Caching-Mechanismen lässt sich aber auch das einigermassen eindämmen.

    //setzt die Optionen für die Java Klasse.
    //hier die FO-Input-Datei und die PDF Output Datei

    $pdf = "output.pdf";
    $fo = "input.fo";
    $options = array($fo,$pdf);  

    //Öffnet eine Verbindung zur Javaklasse org.apache.fop.apps.CommandLine
         
    $java = new Java("org.apache.fop.apps.CommandLine", $options);
     
    //fürt die Javaklasse aus. run() ist eine Methode innerhalb von org.apache.fop.apps.CommandLine
     
    $java->run();
     
    //das pdf liegt als file vor, wir möchtens aber als string, damit wir's an den browser schicken können
     
    $fd = fopen($pdf, "r");
    $pdfcontent = fread( $fd, filesize($pdf) );
    fclose($fd);
    
    //damit der browser schnallt, das nun ein PDF-File kommt, muss man den entsprechenden Header schicken
    
    Header("Content-type: application/pdf\nContent-Length: " . strlen($pdf));
    
    // nun können wir das PDF schicken.
    
    print $pdfcontent;
    

Ein Tutorial zum Thema PHP und Java gibt's hier.

Source zur XML_fo2pdf Klasse: fo2pdf.phps

Ausblick und Diskussion

  • Nun könnte man z.B. eine dynamische RSS-Anwendung entwickeln. RSS steht für Rich Site Summary oder auch RDF Site Summary. Ein Beispiel für eine zurzeit statische RSS-Datei findet man auf der Nomad Website. Weitere Informationen zu RSS findet man hier. Unbedingt beachtenswert in diesem Zusammenhang ist Meerkat von O'Reilly. Siehe dazu auch Rael Dornfests Vortrag zu Meerkat, PHP und XML.

Glossar

Dies ist ein Glossar für die verwendeten Begriffe im Artikel. Weiterführende Links zu diesen Themen finden sie hier.

PHP: Hypertext Preprocessor

PHP ist die Abkürzung für "PHP: Hypertext Preprocessor", eine Skriptsprache, die sich in HTML einbinden lässt. Viele der syntaktischen Möglichkeiten sind den Programmiersprachen C, Java und Perl entnommen und es wurden auch einige PHP-spezifische Features entwickelt. Das Ziel der Sprache ist es, das Schreiben von Programmen zur Erzeugung von dynamisch generierten Seiten zu erleichtern und zu beschleunigen. Hier finden Sie weitere Informationen zu PHP.

Standard Generalized Markup Language

The ISO 8879 standard developed in 1986 to assist electronic delivery and publication of text-based documents. Classified under `Information processing - Text and office systems'. Developed and maintained by the ISO/IEC JTC1 SC18/ WG8 committee. A language is defined for creation of document structure rules in a DTD. Features of the language are either obligatory or optional ( shall be implemented or should be implemented). An SGML document consists of three major parts: the SGML declaration(171), the prolog(007) (containing the DTD) and the document instance set(010).

See Also Extensible Markup Language.

Structured Query Language

Die sogenannte SQL (Structured Query Language) ist eine standardisierte Abfragesprache, die alle Sprachelemente enthält, die erforderlich sind, um sämtliche Arbeiten, die beim Umgang mit einer relationalen Datenbank anfallen, auszuführen.

Extensible Markup Language

Die Extensible Markup Language (XML) ist eine Teilmenge von SGML. Das Ziel ist es, zu ermöglichen, generic SGML in der Weise über das Web auszuliefern, zu empfangen und zu verarbeiten, wie es jetzt mit HTML möglich ist. XML wurde entworfen, um eine einfache Implementierung und Zusammenarbeit sowohl mit SGML als auch mit HTML zu gewährleisten. (aus der deutschen Übersetzung der «XML 1.0 Recommendation» des W3C). Hier finden sie weitere Informationen zu XML.

Siehe auch Standard Generalized Markup Language.

Extensible Stylesheet Language Transformations

Als wichtigster Standard neben XML selber bildet sich immer mehr XSLT heraus, der Transformationsteil der Extensible Stylesheet Language (XSL). Mit XSLT ist es sehr einfach möglich, XML Dokumente zwischen verschiedenen strukturellen Modellen zu transformieren. Da XML seine Hauptanwendung immer mehr im Datenaustausch findet, ist eine universelle und effiziente Methode zur Konvertierung zwischen verschiedenen XML Dokumenten sehr nützlich, und XSLT bietet sich als ideales Werkzeug für diesen Aufgabenbereich an.

Literaturverzeichnis

XML in der Praxis. Professionelles Web-Publishing mit der Extensible Markup Language. Henning Behme and Stefan Mintert. Copyright © 2000 Addison-Wesley Verlag. 2., erweiterte Auflage. 3-8273-1636-7.

XSL und XPath – verständlich und praxisnah. Transformation und Ausgabe von XML-Dokumenten mit XSL. Mike Bach. Copyright © 2000 Addison-Wesley Verlag. 3-8273-1661-8.

XML in a Nutshell. A Desktop Quick Reference. Elliotte Rusty Harold and W. Scott Means. Copyright © 2001 O'Reilly & Associates, Inc . 0-596-00058-8.

XML for the World Wide Web. Visual Quickstart Guide. Elizabeth Castro. Copyright © 2001 Elizabeth Castro. Peachpit Press. 0-201-71098-6.

XSLT . Programmer's Reference. Michael Kay. Copyright © 2000 Wrox Press. 1-861003-12-9.

Professional XML Databases. Kevin Williams, Michael Brundage, Patrick Dengler, Jeff Gabriel, Andy Hoskinson, Michael Kay, Thomas Maxwell, Marcelo Ochoa, Johnny Papa, and Mohan Vanmane. Copyright © 2000 Wrox Press. 1861003587.