Inhaltsverzeichnis
Forschungsorientierte Vertiefung
Das SML Dateiformat
Die Bezeichnung "SML" ist eine Abkürzung für "Simple Markup Language". Das SML-Format wurde zwischen 2001 und 2003 mit dem Ziel entwickelt, eine leicht verständliche und syntaktisch saubere Darstellung zu schaffen, welches von einer breiten Masse der Nutzer akzeptiert werden würde.
SML ist gleichermaßen verwandt mit "JSON" ("JavaScript Object Notation") und "XML" ("Extensible Markup Language"). Es ist semantisch gleich mächtig zu JSON. Dies heißt, alle Konstrukte, welche in JSON ausgedrückt werden können, können ebenso im SML-Format dargestellt werden und umgekehrt. Es ist dennoch wichtig zu betonen, dass SML unabhängig von JSON entwickelt wurde. Beide Dialekte haben keinerlei gemeinsame historische Schnittpunkte.
Vereinfacht ausgedrückt, verwendet SML eine Semantik, vergleichbar mit der von JSON und eine Syntax vergleichbar mit der von XML. Es verbindet somit die unter Nutzern weithin akzeptierte Tag-Darstellung mit einer intuitiven Semantik.
Aufgabe des Dateiformats ist es, nicht-rekursive Datenfelder in Form einer sequentiellen Datei zu repräsentieren. Diese Datenfelder können entweder numerisch oder assoziativ sein und beliebige skalare Werte, oder wiederum andere Datenfelder enthalten, welchen den gleichen Anforderungen genügen müssen. Referenzen sind nicht zugelassen. Objekte werden analog zu JSON dargestellt, indem ihre öffentlichen Objektvariablen in Form eines assoziativen Datenfeldes gespeichert werden. Enthaltene nicht skalare Werte werden rekursiv behandelt.
Zweck dieses Dateiformats ist es, Parameter zu speichern, um Komponenten des Frameworks zu initialisieren. Zweck ist es nicht, größere Datenmengen in diesem Format zu speichern. Insbesondere ist das SML-Format nicht konzipiert als Ersatz für XML.
Unendliche Rekursionen werden nicht erkannt.
Zur Begründung ist Folgendes zu sagen: Der Test, ob eine beliebige Struktur unendliche Rekursionen aufweist ist nicht trivial. Der übliche Ansatz ist eine Pfadprüfung. Dabei fällt jedoch jeweils ein Overhead von T = O(n) Schritten an, wobei n der Länge des Pfades entspricht. Der Beweis dieser unteren Schranke für die Laufzeit ist trivial. Um Overhead zu vermeiden könnte in Betracht gezogen werden, diese Prüfung nur alle x Verarbeitungsschritte durchzuführen, wobei für die positive, ganze Zahl x mit x > 1 ein geeigneter Wert gewählt werden sollte. Trotz dieser potentiellen Optimierung ist damit zu rechnen, dass sich für das gesamte Programm inklusive Pfadprüfung eine quadratische Laufzeit ergibt. Dies ist in für viele Anwendungen jedoch nicht akzeptabel. Aus Gründen der Performance wurde daher absichtlich darauf verzichtet.
An dieser Stelle möchte ich anmerken, dass der naive Ansatz, die Zahl der Elemente zu bestimmen und zu prüfen, ob die Zahl der Iterationen die Zahl der Elemente übersteigt, selbstverständlich nicht praktikabel ist. Um alle Elemente zu "zählen", müsste eine vollständige Traversion durchgeführt werden. Falls diese jedoch einen unendlich rekursiven Pfad enthalten sollte, so würde das Programm niemals terminieren und das Ergebnis wäre somit undefiniert.
Die Aufgabe Dateien für die Initialisierung, beziehungsweise Konfiguration eines Frameworks bereitzustellen, ist nicht ganz trivial. Weil das Framework eine Vielzahl von Plugins besitzen kann, deren Konfigurationsoptionen in den gleichen Dateien abgelegt werden sollen wie die restliche Konfiguration. Anzahl, Struktur, Typ und Benennung dieser Daten ist zur Entwurfszeit jedoch unbekannt. Eventuell sind die Plugins, mit denen das Framework arbeiten wird, zu diesem Zeitpunkt auch noch gar nicht geschrieben. Um unter diesen Umständen überhaupt im Voraus eine sinnvolle DTD oder Schema angeben zu können, ist es nur logisch sich auf natürliche Eigenschaften der Variablen zurückzuziehen. Stabile Eigenschaften wie beispielsweise der Datentyp einer Variable sind geeignet um eine Struktur abzuleiten, welche vorhersagbar ist, weil sie durch stabile syntaktische Eigenschaften von PHP diktiert werden.
Weil PHP nicht streng typisiert ist und Referenzen, sowie Objekte per Definition kein Teil dieser Konfiguration sein dürfen, bleiben die Menge der skalaren Variablen und die Menge der Datenfelder. Dementsprechend werden analog zwei verschiedene Arten von Knoten definiert. Für die Darstellung skalarer Variablen soll der Tag „scalar" eingeführt werden. Dieser darf lediglich CDATA-Abschnitte enthalten – was gerade einem skalaren Kontext entspricht – jedoch keine weiteren Tags, respektive Elemente. Für die Darstellung von Datenfeldern soll der Tag „array" eingeführt werden. Dieser darf wiederum keine CDATA-Bereiche enthalten, sondern lediglich weitere Tags. Diese Tags repräsentieren die Elemente des Datenfelds. Weil XML ein eindeutiges Wurzelelement verlangt, wird zudem der Tag „root" eingeführt. Weitere Tags werden nicht benötigt.
Betrachten Sie das folgende Beispiel, welches zwei Datenfelder darstellt.
<?xml version="1.0" ?>
<!DOCTYPE example SYSTEM "example.dtd">
<root>
<array name="a">
<array name="0">
<scalar name="a"><![CDATA[wert]]></scalar>
<scalar name="b"><![CDATA[wert]]></scalar>
<scalar name="c"><![CDATA[wert]]></scalar>
</array>
<array name="1">
<scalar name="a"><![CDATA[wert]]></scalar>
<scalar name="c"><![CDATA[wert]]></scalar>
</array>
</array>
<array name="b">
<array name="0">
<scalar name="q"><![CDATA[wert]]></scalar>
<scalar name="r" />
<scalar name="s"><![CDATA[wert]]></scalar>
<scalar name="t"><![CDATA[wert]]></scalar>
</array>
</array>
</root>
An diesem Beispiel fallen einige Besonderheiten auf. Erstens ist das Element „root" völlig ohne semantische Bedeutung. Es existiert einzig und allein, weil die Syntax es erfordert.
Etwas künstlich wirken auch die leeren Tags. Sie sind zwar enthalten, aber es ist nicht ganz klar, wie diese in Bezug auf Variablen interpretiert werden sollen. PHP erfordert keine Definition von Variablen vor der ersten Verwendung. Eine Initialisierung einer zuvor nicht existierenden Variable, geschweige einer Konstante, mit „null" ist somit nicht wirklich sinnvoll. Zumal in einer Konfigurationsdatei ein null-Wert semantisch keinen Sinn machen wird. Daher soll per Konvention festgelegt werden, dass auf leere Tags komplett verzichtet werden sollte. Zugriffe auf leere oder nicht existierende Tags werden gemäß der in PHP üblichen Konventionen zu boolean „false" ausgewertet.
Weiterhin ist absehbar, dass diese Darstellung bei größeren Datenmengen unübersichtlich werden könnte. Betrachtet man beispielsweise den Fall, dass ein Datenfeld möglicherweise 50 oder mehr Einträge aufweist, welche zudem eventuell noch tief verschachtelt sind und große CDATA-Abschnitte mit mehreren Zeilenumbrüchen enthalten, dann ist anzunehmen, dass die Lesbarkeit beeinträchtigt wäre. Es wäre für die Lesbarkeit also von Vorteil, wenn aus einem End-Tag direkt ablesbar wäre, welches Element denn nun gerade geschlossen wurde.
Die gesonderte Kennzeichnung der CDATA-Abschnitte, könnte ebenfalls die Lesbarkeit beeinträchtigen, zumal sich der Sinn für den XML-unerfahrenen Laien nicht trivial erschließen muss. Zudem verlangen die zuvor getroffenen Festlegungen explizit, dass an dieser Position ohnehin gar nichts anderes als ein CDATA-Abschnitt folgen darf, weshalb eine Auszeichnung keinen echten Mehrwert bringt, sondern wiederum lediglich eine syntaktische Ursache hat. Es gibt einen seltenen Ausnahmefall, nämlich dass der CDATA-Abschnitt einen schließenden „scalar"-Tag enthält. Diese Fall kann jedoch auch mit Hilfe von Entities umgangen werden, sodass die Kennzeichnung insgesamt obsolete ist.
Abschließend soll die Schreibweise der Tags betrachtet werden. Beispielsweise die Bezeichnung „<array name="b">". Diese Schreibweise könnte auf Laien, überfrachtet und unnötig kompliziert wirken. Denn: dass es sich um ein Datenfeld handeln muss, wird bereits aus der Struktur des Elements deutlich, weil es nur ein einziges anderes Element gibt. Der Tag „scalar" kann aber aus rein syntaktischen Gründen an dieser Stelle gar nicht stehen, weil dieser keine Tags, sondern nur CDATA enthalten darf. Extra zu erwähnen, dass es sich um ein Datenfeld handelt ist somit im Grunde überflüssig. Das Attribut „name" ist allen Tags gemeinsam. Dies ergibt sich zwangsläufig aus syntaktischen Eigenschaften von PHP. Das Attribut entspricht also dem Bezeichner der Variable in PHP. Intuitiver wäre es statt er Bezeichnung „array" oder „scalar" den Bezeichner der Variablen als Tag zu benutzen. Analog gilt die gleiche Betrachtung für den Tag „scalar".
Berücksichtigt man alle diese Einwände so lässt sich folgende vereinfachte Darstellung gewinnen.
<a>
<0>
<a>wert</a>
<b>wert</b>
<c>wert</c>
</0>
<1>
<a>wert</a>
<c>wert</c>
</1>
</a>
<b>
<0>
<q>wert</q>
<s>wert</s>
<t>wert</t>
</0>
</b>
Auch ohne umfangreiche Erläuterung ist erkennbar, dass beide Varianten inhaltlich das Gleiche ausdrücken. Ebenso sollte vermutlich keine Diskussion darüber erforderlich sein, welche der beiden Schreibweisen intuitiver erfassbar, oder leichter lesbar wäre.
Aufgrund ihrer syntaktischen Eigenschaften ist diese Variante jedoch kein wohlgeformtes XML-Dokument mehr. Beispielsweise gibt es mehr als ein Wurzelelement und zudem ist „0" in XML kein gültiger Name für einen Tag. Es war somit notwendig eine andere Bezeichnung zu wählen. Diese Bezeichnung ist „SML" für „simple markup language", in Anlehnung an „XML" („eXtensible markup language").
Gegenüber XML verlangt SML eine Reihe abweichender syntaktischer Eigenschaften. Zunächst ist zu erwähnen, dass die Kodierung einer Datei in UTF-8 oder UTF-16, wie beispielsweise bei XML üblich, leider in vielen Sprachen nach wie vor noch zu Problemen beim Lesen der Dateien führen kann. Zu diesen Sprachen zählen zum gegenwärtigen Zeitpunkt unter anderem Perl 5 und bedauerlicherweise PHP 4. Dies ist zwar ein Versäumnis der Entwickler und keine Eigenschaft von XML als solches, dennoch stellt es einen inakzeptablen Zustand dar, wenn es darum geht eine Anwendung zu initialisieren. Daher ist es sinnvoll für die Zwecke der Initialisierung des Frameworks von der Verwendung dieser Kodierungen abzusehen. Als Zeichensatz wird ISO Latin-1 verwendet. Zeichen, welche darin nicht enthalten sind, sollten durch geeignete Entitäten kodiert werden.
Abweichend von der XML-Syntax wird für SML nicht gefordert, dass das Dokument nur einen einzigen Tags als Wurzelelement enthalten darf. Sollte ein Dokument einen Wald aus mehreren Bäumen enthalten, so werden diese implizit als Kindelemente eines anonymen, virtuellen Wurzelelements enthalten.
Als weitere syntaktische Eigenschaft fordert das SML-Format, dass alle öffnenden Tags durch einen in gleicher Weise benannten schließenden Tag geschlossen werden müssen. Bei der Benennung der Tags kommt es nicht auf die Schreibweise an. Es wird nicht zwischen Groß- und Kleinschreibung unterschieden.
Weiterhin muss per Konvention nach jedem schließenden Tag zwingend ein Zeilenumbruch erscheinen. Vor einem öffnenden Tag dürfen per Konvention lediglich Whitespace-Zeichen eingefügt werden. Ein Tag kann entweder nur Textinhalt („CData") oder weitere Tags enthalten, aber nicht beides gleichzeitig. Falls der Tag einen CDATA-Abschnitt enthält, müssen der Starttag und der Endtag auf der gleichen Zeile sein. Falls der Tag weitere Tags enthält, muss nach dem Starttag ein Zeilenumbruch erfolgen. Zeilenumbrüche in CDATA-Abschnitten können durch die Escapesequenz „\n" ausgedrückt werden.
Alle CDATA-Abschnitte außerhalb eines Tags oder Abschnitte welche nicht der Syntax entsprechen, werden als Kommentare behandelt und bei der Verarbeitung der Datei ignoriert. Eine besondere Markierung von CDATA-Abschnitten oder Kommentaren, wie in XML üblich, entfällt.
Tags können nicht leer sein. Die Verwendung von leeren Tags, beispielsweise „<br />" ist nicht gestattet.
Abschließend soll gelten, dass auf die Verwendung von Attributen verzichtet werden soll.
Der Grund für diese recht restriktive Syntax wird deutlicher bei Betrachtung eines einfachen Beispiels.
Im Folgenden sollen Beispiele beschrieben werden, welche zeigen, auf welche Weise native Datentypen in PHP-Skripten durch das SML-Format darstellbar sind.
Darstellung in PHP-Code:
<?php
$a = 1;
$b = 'string';
$c = 12.5;
$d = true;
?>
äquivalente Darstellung in SML:
<a>1</a>
<b>string</b>
<c>12.5</c>
<d>true</d>
An dieser Stelle ist es wichtig eine syntaktische Einschränkungen von PHP zu verstehen. Eine PHP-Funktion kann nur einen einzelnen Rückgabewert besitzen. (Der Fall, dass der Funktion Parameter per Referenz übergeben werden, wird hier nicht betrachtet.) Eine PHP-Funktion welche den Inhalt des SML-Dokuments auswertet und als Rückgabewert liefert, ist daher gezwungen, die Inhalte in Form eines Arrays zu repräsentieren. Die Inhalte dieses Arrays können wiederum in Variablen innerhalb des Kontext des aufrufenden Programmfragments kopiert werden, wodurch der ursprüngliche Zustand wiederhergestellt wird.
Um ein zweites Beispiel zu nennen: Dokumente in JSO-Notation unterliegen den gleichen Einschränkungen.
Darstellung in PHP-Code:
<?php
$A = array();
$A[0] = 1;
$A[1] = 'string';
$A[2] = 12.5;
$A[1000] = true;
$B = array();
$B[0] = 2;
?>
äquivalente Darstellung in SML:
<A>
<0>1</0>
<1>string</1>
<2>12.5</2>
<1000>true</1000>
</A>
<B>
<0>2</0>
</B>
Darstellung in PHP-Code:
<?php
$SCREEN = array();
$SCREEN["width"] = 1024;
$SCREEN["height"] = 768;
$SCREEN["depth"] = "32-Bit";
?>
äquivalente Darstellung in SML:
<SCREEN>
<width>1024</width>
<height>768</height>
<depth>32-Bit</depth>
</SCREEN>
Darstellung in PHP-Code:
<?php
$A = array();
$A["a"] = 1;
$A["b"] = 2;
$A[0] = "drei";
$B = array();
$B[0] = true;
$B["a"] = 1000;
$B["b"] = array();
$B["b"][0] = 1;
$B["b"][1] = 2;
$B["b"]["a"] = 3;
?>
äquivalente Darstellung in SML:
<A>
<a>1</a>
<b>2</b>
<0>drei</0>
</B>
<B>
<a>1000</a>
<b>
<0>1</0>
<1>2</1>
<a>3</a>
</b>
</B>
Wie aus den obigen Beispielen ersichtlich, eignet sich das beschriebene Format gut um skalare Variablen und Datenfelder darzustellen, welche üblicherweise als Parameter für die Initialisierung des Frameworks in Frage kommen dürften. Die Angabe eines Typs ist nicht erforderlich, weil PHP nicht streng typisiert ist. Der Typ einer Variablen ist zur Laufzeit folglich dynamisch. Die einzige notwendige Unterscheidung findet zwischen skalaren Werten und Datenfeldern statt. Diese Unterscheidung ist trivialerweise anhand der Syntax möglich.
Zu dem für dieses Framework verwendeten SML-Dateiformat gibt es eine Anzahl populärer Alternativen. Der folgende Abschnitt wird einige dieser Alternativen vorstellen, vergleichen und die Ergebnisse diskutieren.
Im Folgenden sollen verschiedene Teilaspekte betrachtet werden:
Da nicht ausgeschlossen werden kann, dass eine Bearbeitung des Quelltextes der Dateien teilweise von Hand erfolgen muss, ist der Lesbarkeit des Quelltextes ein Kriterium, das beleuchtet werden soll. Die Syntax sollte im Idealfall intuitiv zu erfassen sein. Insbesondere ist dies wichtig, da zum gegenwärtigen Zeitpunkt nur für eine Untermenge der Gesamtheit der Konfigurationsmerkmale des Frameworks eine grafische Oberfläche bereitgestellt werden kann. In Anbetracht der Fülle an Optionen ist es darüber hinaus auch auf absehbare Zeit eher unwahrscheinlich, dass eine vollständige Abdeckung erreicht werden kann. Es stellt sich ohnehin die Frage, ob dies überhaupt wünschenswert wäre. Schließlich sollte auch berücksichtigen werden, dass es prinzipiell erfahrene Anwender gibt, welche bewusst und absichtlich auf die Funktionen einer „schwerfälligen" GUI verzichten, weil sie diese eher als Behinderung anstatt als Bereicherung empfinden.
Ein interessanter Faktor die Performance, da das Dateiformat einem eventuell zeitkritischen Zweck genügen soll, nämlich der Initialisierung des Frameworks. Begründet dadurch, dass die Dateien bei jedem Aufruf des Frameworks neu gelesen und dabei eventuell auch durch einen Parser untersucht werden müssen bevor ihre Informationen verfügbar sind, sollte dieser Vorgang mit möglichst geringen Kosten im Hinblick auf die Rechenzeit auskommen. Nicht immer ist ein sinnvoller Vergleich möglich, wo sich ein Vergleich jedoch anbietet sollte er durchgeführt werden.
Darüber hinaus sollten die Grenzen des jeweiligen Dateiformats beachtet werden. Wenn es Faktoren gibt, welche dazu führen können, dass ein Einsatz unter bestimmten Bedingungen nicht mehr sinnvoll ist, sollten diese genannt werden.
Die Portabilität der Dateien in andere Programmiersprachen ist eine der Stärken von XML. Parser für XML sind in den Funktionsumfang nahezu jeder modernen Skript- oder Programmiersprache integriert. Dies fällt jedoch für dieses Anwendungsgebiet – die Initialisierung des Frameworks – nicht ins Gewicht, da die für die Umsetzung des Frameworks gewählte Sprache ist PHP und Implementierungen des Frameworks in anderen Sprachen existieren zurzeit nicht.
Das aktuelle Werkzeug der Wahl zur Behandlung von XML, welches gleichermaßen für PHP 4 als auch PHP 5 verfügbar ist, ist zum gegenwärtigen Zeitpunkt der interne XML-Parser. Dieser XML-Parser besitzt allerdings eine Schwachstelle. Er ist lediglich zum Lesen von XML-Dateien verwendbar, nicht jedoch zum Schreiben. Eine Implementierung zum Erzeugen von XML-Dateien ist erst für PHP ab Version 5 als Standardkomponente enthalten.
Hinzu kommt, dass mithilfe des XML-Parsers ein assoziatives Datenfeld aus einer XML-Datei zu erstellen ähnlich viel Programmieraufwand benötigt, wie für das Schreiben eines Skripts für das Laden einer SML-Datei erforderlich gewesen ist. Allerdings ist dies mit dem Risiko verbunden, dass sich die Implementierung des XML-Parsers in einer späteren Veröffentlichung der Sprache möglicherweise verändert. Zudem gibt es keine sonstigen wesentlichen Vorteile dieser Implementierung, abgesehen von der allgemeinen Beliebtheit von XML als Dialekt.
Als weiteres Argument wäre die Performance zu beleuchten. Dies gestaltet sich jedoch alles andere als unproblematisch und die Ergebnisse sind nur unter Vorbehalt zu betrachten, da diese abhängig sind vom eingesetzten Werkzeug. Derer gibt es viele für das XML-Format, selbst wenn sich auf PHP als solches beschränkt wird.
Um einen Vergleich anstellen zu können, soll ein einfaches XML-Dokument geladen und in ein Datenfeld übertragen werden.
Zum Vergleich hier der Quelltext des verwendeten XML-Dokuments.
<?xml version="1.0"?>
<root>
<array name="channel">
<scalar name="title">Test</scalar>
<scalar name="link">about:blank</scalar>
<scalar name="description" />
<scalar name="language">de-de</scalar>
<array name="0">
<scalar name="title">Testeintrag 1</scalar>
<scalar name="pubDate">Do, 9 Jun 2005 13:23:18 +0200</scalar>
<scalar name="description"><![CDATA[Testeintrag]]></scalar>
<scalar name="link" />
<scalar name="author">Testautor</scalar>
</array>
<array name="1">
<scalar name="title">Testeintrag 2</scalar>
<scalar name="pubDate">Do, 9 Jun 2005 13:23:53 +0200</scalar>
<scalar name="description"><![CDATA[Testeintrag]]></scalar>
<scalar name="link" />
<scalar name="author">Testautor</scalar>
</array>
<array name="2">
<scalar name="title">Testeintrag 3</scalar>
<scalar name="pubDate">Do, 9 Jun 2005 13:24:18 +0200</scalar>
<scalar name="description"><![CDATA[Testeintrag]]></scalar>
<scalar name="link" />
<scalar name="author">Testautor</scalar>
</array>
<array name="3">
<scalar name="title">Linktest</scalar>
<scalar name="pubDate">Do, 9 Jun 2005 13:24:36 +0200</scalar>
<scalar name="description"><![CDATA[Testeintrag]]></scalar>
<scalar name="link">about:blank</scalar>
<scalar name="author">Testautor</scalar>
</array>
</array>
</root>
Anschließend das Gleiche im SML-Format.
<channel>
<title>Test</title>
<link>about:blank</link>
<language>de-de</language>
<0>
<title>Testeintrag 1</title>
<pubDate>Do, 9 Jun 2005 13:23:18 +0200</pubDate>
<description>Testeintrag</description>
<author>Testautor</author>
</0>
<1>
<title>Testeintrag 2</title>
<pubDate>Do, 9 Jun 2005 13:23:53 +0200</pubDate>
<description>Testeintrag</description>
<author>Testautor</author>
</1>
<2>
<title>Testeintrag 3</title>
<pubDate>Do, 9 Jun 2005 13:24:18 +0200</pubDate>
<description>Testeintrag</description>
<author>Testautor</author>
</2>
<3>
<title>Linktest</title>
<pubDate>Do, 9 Jun 2005 13:24:36 +0200</pubDate>
<description>Testeintrag</description>
<link>about:blank</link>
<author>Testautor</author>
</3>
</channel>
Zum Vergleich wird PHP 4 mit dem im Standard enthaltenen XML-Parser herangezogen. Dabei wird so vorgegangen, dass vor und nach jedem Parsen jeweils mithilfe des Befehls „microtime" eine Messung durchgeführt wird. Die Differenz zwischen beiden Werten wird in Millisekunden ausgegeben. Es kommt dabei nicht darauf an, wie viele Millisekunden die eine oder andere Technik schneller ist. Das objektiv zu beurteilen ist mit diesem Testverfahren selbstverständlich unmöglich, denn das Verfahren ist viel zu rudimentär um repräsentative Ergebnisse zu liefern.
Die Konfiguration des Testsystems kann in diesem Fall vernachlässigt werden, da lediglich die Größenordnung der Differenz zwischen beiden Techniken betrachtet werden soll. Zwar hängt die Größe der Messung
Äußert problematisch für eine objektive Bewertung ist zudem der unglückliche Umstand, dass der XML-Parser zur Behandlung der Start-Tags, End-Tags und CDATA-Bereiche Einschübe aus handgeschriebenem PHP-Code benötigt. Es wäre somit denkbar, dass Effekte durch mehr oder minder performanten PHP-Code das Ergebnis der Messung verfälschen. Daher wird der XML-Parser sowohl einmal mit einer vergleichbaren Implementierung, als auch ein zweites Mal zum Vergleich ohne irgendeine Implementierung gemessen.
Zudem ist das Skript zum Lesen der SML-Dateien ebenfalls von Hand erstellt. Es ist hier ebenso möglich, dass die Implementierung nicht optimal gewählt wurde.
Ziel des Tests ist es daher nicht ein Votum für oder gegen den Einsatz des XML-Parsers. Vielmehr soll sich zeigen, ob es deutliche Unterschiede zwischen beiden Varianten gibt. Insbesondere, ob die SML-Variante um Größenordnungen langsamer als der XML-Parser ist. Dies könnte einen Hinweis darauf liefern, dass die gefundene Lösung möglicherweise aus Gründen schlechter Performance nicht für das Framework geeignet sein könnte.
Für diese recht bescheidene Aufgabenstellung sollte diese äußert einfache Testmethode trotz allem ausreichend genaue Ergebnisse liefern.
XML-Parser 1 | XML-Parser 2 | SML-Skript | Differenz SML zu XML 1 | Differenz SML zu XML 2 |
---|---|---|---|---|
0,003685s |
0,001813s |
0,001626s |
-0,001153s (31%) |
-0,000187s (10%) |
0,003410s |
0,001666s |
0,001255s |
-0,002155s (63%) |
-0,000411s (24%) |
0,003367s |
0,001629s |
0,001312s |
-0,002055s (61%) |
-0,000317s (19%) |
0,003394s |
0,001614s |
0,001240s |
-0,002154s (63%) |
-0,000374s (23%) |
0,003381s |
0,001618s |
0,001228s |
-0,002153s (63%) |
-0,000390s (24%) |
0,003386s |
0,001613s |
0,001400s |
-0,001986s (59%) |
-0,000213s (13%) |
0,003387s |
0,001620s |
0,001296s |
-0,002091s (61%) |
-0,000324s (20%) |
0,003658s |
0,001617s |
0,001247s |
-0,002411s (65%) |
-0,000370s (22%) |
0,003678s |
0,001633s |
0,001454s |
-0,002224s (60%) |
-0,000179s (10%) |
0,003725s |
0,001613s |
0,001573s |
-0,002152s (58%) |
-0,000040s (2%) |
Vergleich der Performance zwischen XML-Parser und SML-Skript (Auszug)
1XML-Parser bei Verwendung einer zum SML-Skript vergleichbaren Implementierung
2XML-Parser im Leerlauf, ohne Verarbeitung der Eingabe
Betrachtet man den obigen, kurzen Auszug der Ergebnisse so fällt einerseits auf, dass der mit PHP-Code bestückte XML-Parser weniger performant agiert hat als das SML-Skript. Dies könnte jedoch wie bereits erwähnt auch eine Frage weniger performanter Programmierung sein. Betrachtet man jedoch Spalte 2 („XML-Parser 2") im Vergleich zu Spalte 3 („SML-Skript") so sieht man, dass auch in diesem Fall die SML-Variante nah bei den Werten des XML-Parsers liegt. Dies ist insbesondere bemerkenswert, da der XML-Parser in diesem Fall gar kein Ergebnis produzierte, da keine Implementierung zur Bearbeitung des Inhalts angegeben wurde. Aus diesem Grunde kann das Argument, dass eine ungünstig gewählte Implementierung den XML-Parser verlangsamt haben könnte, nicht mehr aufrecht erhalten werden.
Dieser Test lieferte folglich keinen Hinweis darauf, dass die Leistungsfähigkeit der Implementierung einen negativen Effekt auf die Performance der gesamten Anwendung ausüben könnte.
Trotz allem sind solche Implementierungen nur äußerst schwer vergleichbar. Der Logik folgend, sollte eine in die Programmiersprache integrierte Komponente, wie der hier verglichene XML-Parser, betreffend der Performance stets Vorteile besitzen gegenüber einer Variante, welche in der Sprache selbst geschrieben ist. Der XML-Parser benötigt jedoch immer wieder Aufrufe von PHP-Code, zur Bearbeitung der angetroffenen Elemente. Wie stark dies den Parser möglicherweise ausbremst lässt sich nur erahnen. Zum Vergleich hilft die Betrachtung der in PHP 5 eingeführten Erweiterung „SimpleXML". Sie basiert auf der Erweiterung „libxml" für PHP 5. Diese Erweiterung führt das Parsen der Datei geschlossen aus, dass heißt ohne Aufrufe von PHP-Code, und stellt den Dateiinhalt in einer ähnlichen Form dar, wie das Skript zum Lesen der SML-Dateien. Diese Erweiterung liefert durchschnittlich eine etwa um den Faktor 1,5 bessere Performance.
Allerdings bleibt einzuwenden, dass das von SimpleXML produzierte Ergebnis noch nicht identisch ist mit dem des Skripts. Damit die Ergebnisse vergleichbar wären müsste nachträglich, wiederum durch handgeschriebenen PHP-Code, eine Anpassung vorgenommen werden. Falls dieser Vorgang und sein Einfluss auf die Performance insgesamt berücksichtigt werden sollte, so wäre absehbar, dass sich das positive Gesamtbild im Falle von SimpleXML ebenfalls relativieren könnte.
Syntaktisch gesehen unterscheidet sich die Benutzung von SimpleXML für den Entwickler nur unwesentlich von der Verwendung des SML-Skripts, wie der nachfolgende Quellcodeauszug verdeutlicht.
<?php $sml = SML::getFile("test.config"); $xml = simplexml_load_file("test.xml"); ?>
Der einzige offensichtliche Unterschied liegt im Typ des Rückgabewerts. Während
die SML-Variante ein assoziatives Datenfeld als Ergebnis liefert, gibt SimpleXML
ein Objekt vom Typ „SimpleXMLElement" zurück. Man mag geteilter Auffassung
darüber sein, welche Variante die glücklichere Wahl ist.
Unglücklicherweise ist die Erweiterung SimpleXML derzeit leider nur unter PHP 5 verwendbar und steht für PHP 4 nicht zur Verfügung. Für das Framework ist Abwärtskompatibilität zu PHP 4 jedoch ein wünschenswerter Faktor. Der Grund weshalb die Kompatibilität zu PHP 4 weiterhin gewährleistet werden soll besteht darin, dass der Ast der Version 4 weiterhin von den Entwicklern gepflegt wird. Solange diese Versionspflege fortgesetzt wird, ist auch davon auszugehen, dass PHP in der Version 4 weiterhin Einsatz auf vielen Servern finden wird.
Als persönliche Anmerkung sei mir gestattet zu ergänzen, dass die Entwicklung des SML-Formats historisch vor der Einführung von SimpleXML lag und ich persönlich aus Gründen der Performance eine große Sympathie für die Lösung SimpleXML hege.
Allerdings gibt es auch Kritik. So bildet SimpleXML die Namen von Tags und Attributen auf Namen von Objekten und der Eigenschaften in PHP ab. Das ist problematisch, weil diese in PHP und XML jeweils unterschiedliche Zeichen enthalten dürfen. Zum Beispiel betrifft dies das Zeichen '-', welches in PHP nicht für die Benennung von Variablen verwendet werden darf. Folglich kann man zum Zeitpunkt der Erstellung dieses Dokuments über SimpleXML auf einen Tag namens <foo-bar> nur sehr umständlich zugreifen.
Es ist absehbar, dass sich SimpleXML zukünftig für viele Projekte zum Mittel der Wahl entwickeln könnte.
Initialisierungsdateien, häufig abgekürzt mit der Dateiendung „ini", sind ihrerseits eine geeignete Alternative, sofern keine Abbildung von komplexen Strukturen erforderlich ist. Die Darstellung von Schlüsseln, insbesondere bei tief verschachtelten Informationen, kann jedoch im Einzelfall unübersichtlich werden. Das Format bietet syntaktisch einen einfachen Aufbau. Allerdings müssen dem Format einige Abstriche gegenüber XML zugestanden werden. Es fehlt zum Beispiel die typische Schreibweise in Form von Tags, welche derzeit populär ist. Das Erstellen einer DTD oder einer vergleichbaren Datei, welche die Struktur des Dateiformats beschreibt, ist sowohl praktisch als auch aus theoretischen Überlegungen heraus nicht möglich. Dies ist jedoch kein Nachteil. Bedenkt man, dass die vordergründige Aufgabe dieses Dateiformats darin besteht, eine Abbildung von beliebig strukturierten assoziativen Datenfeldern aus einer Skript- oder Programmiersprache heraus auf ein Dateiformat zu realisieren, wird deutlich, dass die Vorgabe einer statischen Struktur nicht sinnvoll ist. Eine solche Flexibilität wäre in XML ebenfalls denkbar. Eine geeignete DTD würde trivialerweise ein einzelnes Element definieren, welches beliebig oft in sich selbst enthalten sein dürfte. Obwohl dies offensichtlich möglich ist, widerspricht dieser Schritt eigentlich einer Grundintention von XML. Dies würde den eigentlichen Vorteil der Validierbarkeit des Dokuments quasi zunichte machen. Ideal wäre folglich eine Kombination, welche die Vorteile beider Formate in sich vereint.
Der folgende Quellcodeauszug zeigt ein Beispiel für eine Initialisierungsdatei.
[STORE\0]
type=book
author=Dr. A Beispiel
[STORE\0\TITLE]
main=Protomaterie
subtitle=Alpha et Omega
[STORE\1]
type=cd
author=Barbara Sänger
[STORE\1\TITLE]
main=Best-Of
Eine weitere Alternative ist die Verwendung von JSON. Im Folgenden ein Beispiel:
"STORE" : {
"0" : {
"type" : "book",
"author" : "Dr. A Beispiel",
"TITLE" : {
"main" : "Protomaterie",
"subtitle" : "Alpha et Omega"
}
},
"1" : {
"type" : "cd",
"author" : "Barbara Sänger",
"TITLE" : {
"main" : "Best-Of"
}
}
}
PHP bietet die Möglichkeit, ähnlich wie beispielsweise Java, mit den Befehlen „serialize" und „unserialize" Variablen zu serialisieren und wiederherzustellen.
Der folgende Quellcodeauszug zeigt ein Beispiel.
a:1:{s:7:"CHANNEL";a:7:{s:5:"TITLE";s:4:"Test";s:4:"LINK";s:11:"about
:blank";s:8:"LANGUAGE";s:5:"de-de";i:0;a:4:{s:5:"TITLE";s:13:"Testein
trag 1";s:7:"PUBDATE";s:29:"Do, 9 Jun 2005 13:23:18 +0200";s:11:"DESC
RIPTION";s:11:"Testeintrag";s:6:"AUTHOR";s:9:"Testautor";}i:1;a:4:{s:
5:"TITLE";s:13:"Testeintrag 2";s:7:"PUBDATE";s:29:"Do, 9 Jun 2005 13:
23:53 +0200";s:11:"DESCRIPTION";s:11:"Testeintrag";s:6:"AUTHOR";s:9:"
Testautor";}i:2;a:4:{s:5:"TITLE";s:13:"Testeintrag 3";s:7:"PUBDATE";s
:29:"Do, 9 Jun 2005 13:24:18 +0200";s:11:"DESCRIPTION";s:11:"Testeint
rag";s:6:"AUTHOR";s:9:"Testautor";}i:3;a:5:{s:5:"TITLE";s:8:"Linktest
";s:7:"PUBDATE";s:29:"Do, 9 Jun 2005 13:24:36 +0200";s:11:"DESCRIPTIO
N";s:11:"Testeintrag";s:4:"LINK";s:11:"about:blank";s:6:"AUTHOR";s:9:
"Testautor";}}}
Diese Lösung ist ohne Zweifel sehr performant. Der Befehl „unserialize" arbeitet mit dieser Eingabe noch einmal um den Faktor 2 schneller als SimpleXML. Problematisch ist jedoch die Lesbarkeit des erzeugten Datenstroms. Für händische Eingriffe ist diese Darstellung offensichtlich denkbar ungeeignet. Da eine gute Lesbarkeit für das Framework jedoch unabdingbar ist, wurde von einer Realisierung in dieser Form bis auf Weiteres abgesehen.
yana framework by:Thomas Meyer, www.yanaframework.net