28 Beiträge rss

PHP 5/CSS: Word-Dokumente einfach ins Web bringen

Schon seit vielen Versionen von Word ist die Ausgabe eines Dokuments im HTML-Format Problem. Zumindest theoretisch - denn tatsächlich ist der erzeugte Code völlig mit Tags überfrachtet, so dass die Integration dieser HTML-Erzeugnisse in eigene Webseiten keine Freude macht.

(erschienen in der Internet Professionell 12/2004)

Was zum bequemen Bestücken eines Blog oder CMS also fehlt, ist eine Export-Variante, die leichtgewichtigen HTML-Code erzeugt – am besten noch mit CSS-Unterstützung, um die Formate zentral zu verwalten.

Word2html1

So sieht ein Word-Dokument aus, das als XML gespeichert wurde. Alle für das Skript nicht notwendigen Teile sind eingeklappt.

Basierend auf der aktuellen Word-Version 2003 ist dies mit dem Mitteln von PHP 5 einfach möglich. Denn die Dokumente lassen sich aus Word heraus im XML-Format speichern. Das kann dank der in PHP 5 integrierten SimpleXML-Funktionen einfach durchgekaut und entsprechend aufbereitet in HTML-Form wieder ausgegeben werden.

Das XML-Format von Word nutzen

Ziel des hier vorgestellten Skripts ist die Unterstützung von CSS. Dazu werden die im Word-Text verwendeten Druckformatnamen herangezogen und zu class-Verweisen umgewandelt. Allerdings muss man selbst für die Erzeugung der CSS-Datei sorgen, damit jedes Word-Format ein eine Entsprechung in der CSS-Datei besitzt.

Das Skript ist so angelegt, dass man ihm per Parameter den Namen der Word-Datei sowie den Namen der CSS-Datei übergibt. Über optionale Zusatzparameter kann man sogar noch Formatnamen angeben, deren Ausgabe unterdrückt werden soll. Nützlich ist dies beispielsweise dann, wenn manche Elemente nur bei der Nutzung des Dokuments als Ausdruck sinnvoll sind. In unserem Beispielartikel ist das der Text, der mit dem Format "Leserführung" ausgezeichnet ist, Dies ist die Zeile ganz oben im Heft, die zur einfacheren Orientierung beim Durchblättern dient. Im Browser bringt das nichts und kann daher entfallen.

Neben dem PHP-Skript finden Sie auf der Heft-CD als Beispieldokument einen Artikel aus einer vergangenen Heftausgabe zusammen mit einem beispielhaften CSS-File.

So funktioniert´s

Die Funktion extract_paragraphs() übernimmt die Hauptarbeit des Umwandlungsskripts. Der Rest des Skripts dient lediglich der Ermittlung übergebener Parameter und der Bildung des HTML-Grundgerüsts für die Ausgabe. Zu Beginn von extract_paragraphs() wird die als XML gespeicherte Word-Datei über diesen Aufruf eingelesen.

$objXml = @simplexml_load_file($strFilename);

Der Dateiname wurde im Hauptprogramm über den Aufrufparameter "quelle" ermittelt und an die Funktion übergeben. Im einfachsten Fall gibt man dabei eine lokal auf dem Server residierende Datei an. Dank der so genannten "fopen-wrappers" von PHP, klappt das aber genauso mit einem http- oder FTP-Quelldokument über die Verwendung der URL-Syntax. Das Programm muss sich um die Unterscheidung der Datenquellen nicht kümmern, weil dies völlig von PHP behandelt wird.

Noch erwähnenswert: Der Aufruf von simplexml_load_file() wird, wie gezeigt, von einem @ eingeleitet. Das bewirkt im Fehlerfall die Unterdrückung der Warnmeldung von PHP. Diese Meldung wird gegebenenfalls in den nächsten beiden Zeilen vom Skript selbst in besser verständlicher Form nachgeholt, als die "hauseigene" Warnung von PHP.

Die nächsten beiden Zeilen finden alle Knoten im XML-File heraus, die einem Absatz im Word-Dokument entsprechen:

$path_para='//w:p';

foreach($objXml->xpath($path_para) as $para) {…}

Dabei wird in der ersten Zeile die Suchmaske für die gewünschten XML-Knoten festgelegt. (Ein nützliches Tutorial zur dabei verwendeten Xpath-Syntax finden Sie auf http://www.zvon.org/xxl/XPathTutorial/General/examples.html)

Tatsächlich befinden sich die Tags der Form , die im Word-Dokument einen Absatz einleiten, tief eingebaut in der XML-Hierarchie. Der doppelte Schrägstrich bewirkt hier aber, dass die entsprechenden Knoten gefunden werden, egal wie die darüberliegenden XML-Äste lauten.

Das foreach-Konstrukt durchläuft alle gefundenen Absätze, wobei der Inhalt der Variablen $para bei jedem Durchlauf dem aktuellen Absatz-Knoten entspricht.

Namensräume beachten

Um den nächsten Codeteil verstehen zu können, muss man sich ein wenig mit den "namespaces" beschäftigen. Dieses Konzept, das es in vielen Programmiersprachen gibt, sorgt dafür, dass gleichlautende Bezeichner aus verschiedenen Teilbereichen nicht zu Problemen führen, wenn sie in einem Projekt gemeinsam zum Einsatz kommen. Meist bekommen dazu die verwendeten Bezeichner einfach ein unterschiedliches Präfix verpasst – wie auch hier bei den Word-Dateien: Alle Word-spezifischen Tags beginnen mit "w:" (die allgemein Microsoft-Office zugewiesenen Tags tragen übrigens ein "o:" im Namen). Jeder offizielle Namensraum wird in einer XML-Schemadatei definiert. Für Word-Dateien ist das zum Beispiel das Dokument 'http://schemas.microsoft.com/office/word/2003/wordml'.

Das Präfix w: kam auch weiter oben schon zum Vorschein, bei der Xpath-Suchmaske. Während es dort allerdings einfach mit in den Suchstring aufgenommen werden konnte, klappt das bei den nun gewünschten SimpleXML-typischen Zugriffen in Objektmanier nicht mehr. Denn wenn man hier den Doppelpunkt mit angeben würde, bekäme man sofort von PHP einen Syntax-Error um die Ohren gehauen.

Mit Trick zum Ziel

Man kann das Namespace-Präfix allerdings mit einer Maßnahme loswerden, die im PHP-Manual so nicht zu finden ist. Angelpunkt dafür ist die Methode children() mit der alle Unterknoten eines SimpleXML-Objekts zurückgeliefert werden. Gibt man hier als Parameter die Schemadatei an, unterdrückt SimpleXML bei den Rückgabewerten den Präfix-Teil.

So kann man sich dann in der Variablen $para_children alle Tochterknoten eines Absatz-Objekts zurückliefern lassen und erhält den Namen des zugrunde liegenden Formats über folgenden Ausdruck:

$style = $para_children->pPr->pStyle['val'];

Dabei ist der letzte Teil in eckigen Klammern notwendig, weil der Name des Formats nicht als Inhalt der Tags zu finden ist, sondern als Attribut "val" des öffnenden Tags. Der Screenshot, der den interessanten Ausschnitt des Word-Dokuments darstellt, zeigt dies ganz gut.

Brauchbares aussortieren

Nun durchläuft eine weitere foreach-Schleife die ermittelten Unterelemente des Absatzknotens und sortiert aus, was zur Ausgabe gelangen soll. Das sind einerseits alle einfachen Textteile, sowie die Hyperlinks, die im erzeugten HMTL gleich in Tags der Form <a href...> eingebettet werden sollen.

foreach($para_children as $name=>$para_child)

Der Ausdruck hinter dem "as" ist in diesem Fall keine einfache Schleifenvariable, sondern die PHP-typische Kombination aus Schlüssel und Wert. Der Schlüssel entspricht hierbei dem ersten Tag des jeweiligen Unterelements, das dringend zur Fallunterscheidung gebraucht wird.

Lautet dieses Tag dann handelt es sich beim Element um normalen Text, der dann im untergeordneten Tag zu finden ist. Ein "hlink" dagegen zeigt ein Hypertext-Link an. Dessen Zieladresse findet sich im Attribut "dest" und der dargestellte Linktext wie beim normalen Text in der Tag-Hierarchie , nur eben hierbei dem Tag untergeordnet.

Word2Html2

So sieht der als Beispiel verwendete Artikel in der HTML-Ansicht aus. Über den Parameter "surpress" sind dabei bestimmte Absatztypen ausgeblendet worden.

Je nach festgestelltem Element fügt der Rumpf der foreach-Schleife der Variablen $content entweder nur den Textteil oder das Hypertext-Link hinzu. Durch Anwendung der Funktion utf8_decode() wird die im XML-File angewendete Kodierung von Umlauten und Sonderzeichen wieder zurückgenommen.

Ergebnisse ausgeben

Sind alle Unterelemente des aktuellen Absatz abgearbeitet, wird der gesammelte Inhalt in einem Tag -Pärchen

geklammert ausgegeben. Dabei erhält der Klassenname den zuvor festgestellten Namen des Word-Druckformats. Der ist übrigens von Word um alle Umlaute beraubt worden. Dass dennoch beim Wiedereinladen eines Word-Textes im XML-Format alle Umlaute in den Formatnamen erscheinen, liegt an einer Umsetzungstabelle im Abschnitt des Dokuments, die den gekürzten Namen die angezeigten zuordnet.

Die Ausgabe des Absatzes erfolgt allerdings nur, wenn das Format nicht in der "Schwarzliste" vorkommt. Die definiert man über den optionalen Parameter surpress=… beim Aufruf des Skripts. Dies dient dazu, über den Formatnamen bewusst bestimmte Textteile ausblenden zu können, weil sie etwa in der HTML-Form des Textes keinen Sinn ergeben. Sollen mehrere Formatnamen geblockt werden, muss man die Array-Form verwenden und den Parameter mehrmals aufführen, wie in

…&surpress[]=Format1&surpress[]=Format2

Das Skript bekommt dann ein Array surpress[] geliefert, das aus den beiden Strings "Format1" und "Format2" besteht. Über die Funktion in_array() wird im Skript dann geprüft, ob der Formatname des aktuellen Absatz im Array vorkommt.

Großzügig geht das Programm man mit vergessenen eckigen Klammern bei der Nennung eines einzigen unterdrückten Formats um und wandelt dessen Name selbständig in ein Array, das dann eben nur aus einem einzigen Element besteht. Ansonsten würde die PHP-Funktion in_array() mit einer Fehlermeldung abbrechen, weil sie mit einem String statt einem Array gefüttert wird.

XSL als Alternative

Während die zuvor vorgestellte Lösung zur Konvertierung eines Word-Dokuments nach HTML per PHP-Programm den XML-Code durchwühlt, gibt es noch einen ganz anderen Ansatz: Eine XSL-Datei soll die XML-Vorlage durch die Anwendung von Transformationsregeln Web-fähig machen.

Wer sich schon einmal den komplizierten Aufbau von Word-Texten in XML-Format angesehen hat, weiß, dass die Umsetzung keine leichte Aufgabe sein kann. Gottseidank hat Microsoft aber so ein XSL-File mit Namen word2xml.xsl schon selbst geschaffen. Das mit über 200 kByte dann auch recht üppig ausgefallene Werk ist im kostenlosen Produkt

Wer im Gegensatz zur hier vorgestellten Lösung eine Umsetzung nahezu aller Möglichkeiten sucht, ist damit besser beraten. Die originale URL von Microsoft kann man leider niemandem zumuten, darum hier die Adresse eines Redirectors.

Word2Html3

Zum Vergleich der Beispielartikel in der Word-Ansicht. Die erste Zeile mit der Leserführung erscheint hier, während das Skript sie bewusst unterdrückt.


Bedingungen für die Kommentareingabe
Hinweis



Ihr Kommentar:


Name: E-Mail:
Name und E-Mail in einem Cookie auf Ihrer Festplatte speichern

Copyright © schraudolph.de 1999-2012   | Tippscout 4.0
Zurück Home