PHP/SAX
Funktionsübersicht
Die folgenden Funktionen steuern den Parser.
Funktion | Beschreibung |
---|---|
xml_parser_create | Erzeugt eine neue Instanz des XML-Parsers und gibt ein Handle zurück, das von anderen Funktionen benötigt wird. |
xml_parse | Startet das Parsen eines Dokuments. |
xml_get_error_code | Zeigt Fehlernummern an. |
xml_error_string | Zeigt Fehlermeldungen an. |
xml_get_current_line_number | Gibt die aktuell vom Parser untersuchte Zeile des XML-Dokuments aus. |
xml_get_current_column_number | Gibt die aktuell vom Parser untersuchte Spalte des XML-Dokuments aus. |
xml_get_current_byte_index | Gibt den aktuellen Byte-Index des XML-Dokuments aus. |
xml_parser_free | Gibt einen Parser wieder frei. |
xml_parser_set_option | Setzt verschiedene Optionen. |
xml_parser_get_option | Ermittelt die aktuellen Werte der Optionen. |
utf8_decode | Wandelt eine UTF-8-Zeichenkette nach ISO-8859-1 um. |
utf8_encode | Wandelt eine ISO-8859-1-Zeichenkette nach UTF-8 um. |
Mit den folgenden Funktionen können eigene Routinen definiert werden, um bei der Verarbeitung von XML-Dokumenten auf bestimmte Daten zu reagieren. Dabei wird eine weitere - benutzerdefinierte - Rückruffunktion namentlich angegeben. Diese ist letztlich für die Verarbeitung der Ereignisse zuständig, di beim Abarbeiten des Dokuemnts auftreten.
Funktion | Beschreibung |
---|---|
xml_set_selement_handler | Die hier definierte Funktion wird ausgeführt, wenn der Parser ein XML-Element erreicht oder eines verlässt. Start- und End-Tags sowie der Inhalt dazwischen werden getrennt behandelt. |
xml_set_character_data_handler | Diese Funktion behandelt alle Zeichen, die nicht als Tag gelten. Das betrifft auch "weisse Leerzeichen". |
xml_set_processing_instruction_handler | Hiermit werden Prozessanweisungen, die wie "<?get ... ?>" aussehen, behandelt. |
xml_set_default_handler | Die hiermit definierte Funktion wird gestartet, wenn sich keine andere Definition für das Ereignis zuständig fühlt. |
xml_set_unparsed_entity_decl_handler | Diese Funktion behandelt nicht zu parsende Einheiten (NDATA). |
xml_set_notation_decl_handler | Eine Notations-Deklaration wird hiermit behandelt. |
xml_set_external_entity_ref_handler | Diese Funktion ist zuständig, wenn eine externe Referenz gefunden wird. |
Eigenschaften der Funktionen
Umwandlung der Schreibweise
Die als "case folding" bezeichnete Massnahme bezieht sich auf die Anforderung der Ereignisbehandlungsroutinen, die zu untersuchenden Tags in Grossbuchstaben zu erhalten. Entsprechend werden alle XML-Elemente in Grossbuchstaben gewandelt, bevor sie gesendet werden. Der Vorgang kann allerdings mit den beiden Funktionen "xml_parser_get_option" und "xml_parser_set_option" kontrolliert werden, falls ein anderes Verhalten erwünscht ist.
Fehlercodes
Die von der Funktion "xml_parse" ausgegebenen Fehlercodes liegen als Konstante vor.
Fehlercode | Beschreibung |
---|---|
XML_ERROR_NONE | |
XML_ERROR_NO_MEMORY | |
XML_ERROR_SYNTAX | |
XML_ERROR_NO_ELEMENTS | |
XML_ERROR_INVALID_TOKEN | |
XML_ERROR_UNCLOSED_TOKEN | |
XML_ERROR_PARTIAL_CHAR | |
XML_ERROR_TAG_MISMATCH | |
XML_ERROR_DUPLICATE_ATTRIBUTE | |
XML_ERROR_JUNK_AFTER_DOC_ELEMENT | |
XML_ERROR_PARAM_ENTITY_REF | |
XML_ERROR_UNDEFINED_ENTITY | |
XML_ERROR_RECURSIVE_ENTITY_REF | |
XML_ERROR_ASYNC_ENTITY | |
XML_ERROR_BAD_CHAR_REF | |
XML_ERROR_BINARY_ENTITY_REF | |
XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF | |
XML_ERROR_MISPLACED_XML_PI | |
XML_ERROR_UNKNOWN_ENCODING | |
XML_ERROR_INCORRECT_ENCODING | |
XML_ERROR_UNCLOSED_CDATA_SECTION | |
XML_ERROR_EXTERNAL_ENTITY_HANDLING |
Zeichenkodierung
PHP kodiert Zeichen intern imm im Unicode-Format UTF-8 (8 bis 21 Bits in bis zu 4 Bytes). Die Kodierung des Quelltexts muss vor dem Parsen festgelegt werden. Die alternativen zeichensätze US-ASCII und ISO-8859-1 sind 8-Bit-Zeichensätze.
Eine weitere Einstellung ist nach dem Parsen der Tags möglich. Diese als Zielkodierung bezeichnete Wahl des Zeichensatzes erfolgt, wenn die untersuchten Elemente an die Ereignisbehandlungsroutinen geleitet werden. Zeichen, die nicht abgebildet werden können, werden durch ein Fragezeichen ersetzt.
SAX-Anwendungen in der Praxis
Die folgenden Beispiele zeigen, wie XML-Parser selbst geschrieben werden und wie damit Zugriff auf XML-Daten möglich ist. Als Beispieldatei wird dazu die folgende Datei "file.xml" verwendet.
<?xml version="1.0" ?> <!DOCTYPE FirstXML [ <!ELEMENT AUSGABE (ANZEIGE)> <!ELEMENT ANZEIGE (#PCDATA)> ]> <AUSGABE> <ANZEIGE>Jetzt wird's spannend!</ANZEIGE> </AUSGABE>
Das folgende Beispiel zeigt einen einfachen Parser, der nur Tags verarbeitet. Attribute und Daten innerhalb des Containers werden nicht beachtet.
<?php
## Die zur Anzeige gebrachte XML-Datei.
$file = "data/file.xml";
$depth = 0;
## Die eigentliche Funktionalität liegt in den folgenden beiden
## Ereignisbehandlungsroutinen. Jedes öffnende Element wird eingerückt und
## entsprechend beim schliessenden Element wieder ausgerückt. Die Anzahl
## der Einrückungen wird in der globalen Variable "$depth" gespeichert.
function startElement($parser, $name, $attrs)
{
global $depth;
## Wird ein öffnendes Element gefunden, so wird eine Anzahl Leerzeichen
## ausgegeben.
echo str_repeat(" ", $depth * 4);
echo "<$name><br />\n";
#3 Danach wird für die nächste Stufe die Tiefe erhöht.
$depth++;
}
function endElement($parser, $name)
{
global $depth;
## Zurücknehmen der Einrückung
$depth--;
echo str_repeat(" ", $depth * 4);
echo "</$name><br />\n";
}
## Erzeugen eines neuen Parsers, die Referenz "$xml_parser" wird in allen
## anderen Funktionen zum Zugriff genutzt.
$xml_parser = xml_parser_create();
## Zuweisung der Ereignisbehandlungsroutinen. Im einfachsten Fall werdenm
## Start- und End-Tags behandelt. Als Parameter werden die selbst-
## definierten Funktionsnamen angegeben.
xml_set_element_handler($xml_parser, "startElement", "endElement");
if (!($fp = fopen($file, "r")))
{
die("Kann XML-Datei nicht öffnen");
}
## Einlesen der XML-Datei.
while ($data = fread($fp, 4096))
{
## Zeilenweise Interpretation. Die Ausgabe an den Webbrowser erfolgt
## automatisch.
if (!xml_parse($xml_parser, $data, feof($fp)))
{
die(sprintf("XML-Fehler: %s aus Zeile %d",
xml_error_string(xml_get_error_code($xml_parser)),
xml_get_current_line_number($xml_parser)));
}
}
## Zerstörung des Parsers, um die belegten Ressourcen freizugeben.
xml_parser_free($xml_parser);
?>
<p>So zeigt der Webbrowser diese XML-Datei direkt an:
<a href="data/file.xml">file.xml</a></p>
|
<AUSGABE> So zeigt der Webbrowser diese XML-Datei direkt an: file.xml |
Externe Entitäten
Im Gegensatz zum vorigen Beispiel wird im folgenden der Code konkret untersucht und durch farbige Hervorhebung die Reaktion des Parsers kenntlich gemacht. Die im Beispiel verwendete Datei "data.xml" hat folgenden Inhalt.
<?xml version='1.0' standalone="yes"?> <!DOCTYPE chapter [ <!-- Aufforderung zum Lesen eines weiteren Dokuments --> <!ENTITY systemEntity SYSTEM "data/external.xml"> <!ENTITY title "Das ist der Titel"> ]> <chapter> <TITLE>&title;</TITLE> <para> <informaltable> <tgroup cols="3"> <tbody> <row> <entry>a1</entry> <entry morerows="1">b1</entry> <entry>c1</entry> </row> <row> <entry>a2</entry> <entry>c2</entry> </row> <row> <entry>a3</entry> <entry>b3</entry> <entry>c3</entry> </row> </tbody> </tgroup> </informaltable> </para> &systemEntity; <sect1 id="about"> <title>Über diesen Text</title> <para> <!-- Dies ist ein Kommentar --> <?php echo "Hallo! Dies ist PHP Version " . phpversion(); ?> </para> </sect1> </chapter>
Die in der vorigen Datei "data.xml" genannte Datei "external.xml" hat folgenden Inhalt.
<?xml version="1.0" ?> <foo> <element attrib="value"/> <?php $check = phpversion(); print "Hier wurde PHP-Code ausgeführt. PHP-Version: $check"; ?> </foo>
Mit Hilfe des folgenden Skripts kann praktisch gezielt auf alle Elemente der XML-Datei zugegriffen werden. Allerdings wird immer - von oben nach unten - die gesamte Datei verarbeitet. Eine Analyse von Teilen bzw. die gezielte Extraktion von Daten ist nicht ohne weiteres möglich. In der Praxis können derartige Methoden verwendet werden, um fremde Daten in ein eigenes Format oder in eine relationale Datenbank zu überführen. Für die Navigation innerhalb von XML wurde XPath entwickelt, das den Einsatz anderer Module voraussetzt.
Bei der Darstellung im Webbrowser ist hier allerdings etwas nicht sauber...
<?php
## Die zur Anzeige gebrachte XML-Datei.
$file = "data/data.xml";
## Über das ganze Dokument mitgeführte Einrückung. Damit wird die Struktur
## des Dokuments bei der Anzeige besser lesbar.
function indent($addsub = 0)
{
static $depth;
if ($addsub < 0)
{
$indent = str_repeat(" ", $depth * 4);
$depth += $addsub;
return $indent;
}
else
{
$depth += $addsub;
$indent = str_repeat(" ", $depth * 4);
return $indent;
}
}
function startElement($parser, $name, $attr)
{
echo indent(1);
print "<<span class=tag>$name</span>";
if (is_array($attr))
{
foreach ($attr as $k => $v)
{
echo " <span class=attr>$k</span>=";
echo "'<span class=parm>$v</span>'";
}
}
print "><br />\n";
}
function endElement($parser, $name)
{
echo indent(-1);
print "</<span class=tag>$name</span>><br />\n";
}
## Allle Zeichen, die nicht vom Parser behandelt werden, werden fett
## ausgegeben.
function characterData($parser, $data)
{
$data = chop($data);
$indent = indent();
print strlen($data) > 0 ? "$indent<b>$data</b><br />\n" : NULL;
}
## Prozessbehanldung
function PIHandler($parser, $target, $data)
{
## Überprüfung, ob PHP-Code vorhanden ist
switch (strtolower($target))
{
case "php":
## Falls es zulässiger PHP-Code ist, erfolgt die Abarbeitung
## mit der Funktion "eval".
eval($data);
break;
default:
## Ansonsten wird der PHP-Code ienfach ausgegeben, ohne abgearbeitet
## zu werden.
echo htmlspecialchars($data);
}
}
function defaultHandler($parser, $data)
{
$data = chop($data);
echo indent();
if (preg_match("|^&.*;$|U", $data))
{
echo "<u>" . htmlspecialchars($data) . "</u><br />\n";
}
elseif (strlen($data) > 0)
{
echo htmlspecialchars($data);
echo "<br />\n";
}
}
## Die externen Referenzen werden getrennt von der Basisdatei behandelt.
function externalEntityRefHandler($parser, $openEntityNames, $base, $systemId, $publicId)
{
if ($systemId)
{
## Start eines neuen Parsers
if (!list($parser, $fp) = new_xml_parser($systemId))
{
printf("Kann Entity %s in Zeile %s nicht öffnen<br />\n", $openEntityNames, $systemId);
return false;
}
while ($data = fread($fp, 4096))
{
if (!xml_parse($parser, $data, feof($fp)))
{
printf("XML-Fehler: %s in Zeile %d während der Verarbeitung von %s<br />\n",
xml_error_string(xml_get_error_code($parser)),
xml_get_current_line_number($parser),
$openEntityNames);
xml_parser_free($parser);
return false;
}
}
xml_parser_free($parser);
return true;
}
return false;
}
function new_xml_parser($file)
{
$xml_parser = xml_parser_create("ISO-8859-1");
## Definition der Behandlungsroutinen.
xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0);
xml_set_element_handler($xml_parser, "startElement", "endElement");
xml_set_character_data_handler($xml_parser, "characterData");
xml_set_processing_instruction_handler($xml_parser, "PIHandler");
xml_set_default_handler($xml_parser, "defaultHandler");
xml_set_external_entity_ref_handler($xml_parser, "externalEntityRefHandler");
if (!($fp = @fopen($file, "r")))
{
return false;
}
return array($xml_parser, $fp);
}
if (!(list($xml_parser, $fp) = new_xml_parser($file)))
{
die("Kann XML-Datei nicht öffnen");
}
print "<code>";
while ($data = fread($fp, 4096))
{
if (!xml_parse($xml_parser, $data, feof($fp)))
{
die(sprintf("XML-Fehler: %s in Zeile %d<br />\n",
xml_error_string(xml_get_error_code($xml_parser)),
xml_get_current_line_number($xml_parser)));
}
}
print "</code>";
print "<hr>\nParser beendet\n";
xml_parser_free($xml_parser);
?>
<p>Schauen Sie sich hier an, wie der Browser die XML-Dateien selbst darstellt:</p>
<ul>
<li><a href="data/data.xml">data.xml</a></li>
<li><a href="data/external.xml">external.xml</a></li>
</ul>
|
Parser beendet Schauen Sie sich hier an, wie der Browser die XML-Dateien selbst darstellt:
|