Autor: Peter Bieling © 2004
Dieses Tutorial ist bewusst einfach gehalten, um auch Einsteigern die Möglichkeit zu geben, XML mit Hilfe von PHP in ihren Anwendungen zu nutzen. Wer sich unterfordert fühlt, kommt vielleicht über die PDF-Dokumentation, die die Methoden auflistet, schneller zum Ziel.
Wenn Sie die Datei xml-line.zip
herunterladen, finden Sie im Ordner examples nicht nur einfache
sondern auch weiterführende Beispiele, die teilweise hier nur angerissen oder gar nicht erwähnt
sind, weil sie eventuell nachträglich eingefügt wurden. Dem jetzige Downloadpaket liegt die
Version 0.3.5 bei, deren neue Methoden noch nicht dokumentiert sind. Infos und Beispiele
gibt es im Ordner examples-xml-line03.
Kopieren Sie das entpackte Verzeichnis
xml-line (mit den Unterverzeichnissen) am besten in eine lokale Serverumgebung die
PHP unterstützt,
und die Beispiele sollten lauffähig sein. Möglicherweise müssen noch Schreibrechte für
das Verzeichnis output vergeben werden.
Ein erstes vollständiges Beispiel soll zeigen, wie XML-line verwendet wird. Dafür soll uns eine einfache XML-Datei mit ziemlich beliebigem Inhalt als Versuchsobjekt dienen. Es wird dann anschließend für Sie kein großes Problem sein, Ihre eigenes realistisches Testszenario einzurichten.
Bevor wir nun beginnen, dass Dokument zu bearbeiten, Elemente, Attribute und Texte zu ändern, beschränken wir uns für den Anfang erst einmal auf das Auslesen eines Elements. Es soll genau ein obst-Element ausgelesen werden. Da die Datei von vorn bis hinten geparst wird, wird es naturgemäß das erste Element sein, dass wir als Ergebnis erhalten werden.
<?php
require_once("../xml-line.php");
$mylines = new xml_line("xml-files/obst.xml");
$mylines->get_data(1,"obst");
$result = $mylines->xml_stream();
printf("<p>Das Element hat den Wert <b>%s</b>.</p>",
$result[0][0][0]);
?>
Erfreulicherweise lautet das Ergebnis:
Das Element hat den Wert Apfel.
Sie finden das Beispiel auch im Verzeichnis examples im Downloadpaket als obst1.php
Das Beispiel zeigt, wie einfach unter günstigen Bedingungen die Abfrage eines
Wertes sein kann. Gehen wir die Zeilen des Skripts im Einzelnen durch:
Die erste Zeile bindet die Klasse xml-line.php in das laufende Skript ein.
$mylines = new xml_line("xml-files/obst.xml"); Diese Zeile erzeugt eine Instanz
dieser Klasse. Der Parameter gibt an, auf welche XML-Datei zugegriffen wird.
Jetzt erst wird es interessant:
$mylines->get_data(1,"obst"); Die Methode get_data() ermöglicht das Auslesen
von Elementen. Genau gesagt, wird die Bearbeitung hier erst vorbereitet. Es können beliebig
viele weitere Methoden folgen. In diesem Fall wird nur 1 Wert benötigt. Ist dieser erste
Parameter auf 0 gesetzt, werden alle obst-Elemente in die Suche einbezogen. Es würden
also drei Ergebnisse zurückgeliefert.
$result = $mylines->xml_stream(); startet mit xml_stream() das Parsen des Dokuments und
liefert am Ende ein Ergebnisarray zurück, das Informationen zum gesuchten Element enthält.
Die Struktur dieses Arrays sehen wir uns später an.
Ganz so einfach kann und soll es nicht bleiben. Insgesamt können zur Suche eines
bestimmten Elements in get_data() und auch in den meisten anderen bis zu 5 Parameter
übergeben werden, die für das Auffinden eines oder auch mehrerer Elemente zuständig sind.
Und diese können darüber hinaus sehr variabel eingesetzt werden. Selbst gemischte Inhalte,
also z.B. Textteile die mit anderen Elementen abwechseln, lassen sich finden.
Die Parameter sind alle optional. Wenn Sie jedoch den 5. Parameter nutzen wollen, müssen
die vorangegangenen natürlich ebenfalls gesetzt werden. Mit "" geben Sie an, dass dieser
Parameter leer bleiben soll.
Die folgende Tabelle gibt Aufschluss über die Aufgabe der einzelnene Parameter.
Nr. | Bedeutung | Format | Beispielwert | Anmerkungen |
---|---|---|---|---|
1 | Trefferzahl | positive Ganzzahl | 3 | Zahl der Ergebnisse, die für diese Methode gefunden werden sollen. Im Beispiel 3. Danach wird nicht mehr weiter gesucht. Ist im Moment nur für get_data() oder get_attribute() implementiert. Setzen Sie ansonsten den ersten Parameter auf 0 oder "", wenn alle passenden Ergebnisse geliefert werden sollen. |
2 | Elementpfad- Bedingung |
String | wurzel/vater/kind kind wurzel/vater/* */vater/* |
Es ist nicht erforderlich den gesamten Pfad zum gesuchten Element anzugeben. Z.B. such get_data(0,"strong") alle Inhalte, die mit den strong-Tags ausgezeichnet wurden. Will man alle Elemente suchen, die von vater eingeschlossen sind kann man mit dem * als wildcard arbeiten. Dabei kann der * Stern durchaus für mehrere Elemente stehen, z.B. für "kind/kindeskind" oder vorher für "urgrossvater/grossvater". Will man nur eine Ebene auslesen, kann man sich mit dem 5. Parameter, dem Elementzählpfad behelfen |
3 | Pattern- Bedingung |
String | Flasche Bier | Dieser Parameter hat für die Klasse sicherlich noch Ausbaupotential. Im Moment werden z.B. mit get_data(0, "","Flasche Bier") alle Elemente gefunden, die diesen String enthalten, so z.B. auch den denkwürdigen Satz "Hol mir mal ne Flasche Bier". Wer nur die Einträge sucht, die den kompletten Satz enthalten, kann entweder die Ergebnisse filtern oder sich die Klasse entsprechend anpassen, was keine unlösbare Aufgabe ist. Noch einmal: ein leerer Parameter, den Sie mit "" setzen, bedeutet, dass keine Bedingung für den Wert gestellt wird. Es ist also egal, welcher Wert enthalten ist. |
4 | Attribut- Bedingung |
Array | array("zustand"=>"neu", "preis"=>"3,15 EUR";) | get_data(0, "Rosis_Kinder/kind", "", array("vater"=>"Robert")) findet alle Kinder von Rosi, deren Vater Robert ist. Wenn mehrere Attribute und Werte angegeben werden, müssen alle Bedingungen erfüllt sein. Der Wert muss exakt sein. "Roberts Freund" würde nicht akzeptiert. Auch hier gibt es theoretisch noch Entwicklungsmöglichkeiten. Da die Attribute aber ohnehin im Ergebnisarray mitgeliefert werden, kann man auch später noch weiter filtern. |
5 | Element- Zählpfad- Bedingung |
String | 1-3-2 1-3-{3 to 7} 1-3-{3,8,12} 1-3-{*} 1-{*}-2 1-3-2:4 :4 |
Mit dieser Bedingung steht ein mächtiges Instrument zur Verfügung, um Werte mit Hilfe einer
vorher definierten Zahnung auszukämmen. get_data(1, "adressen/eintrag/name", "","","1-3-1")
Da es nur ein Wurzelelement gibt, steht dieser Wert naturgemäß auf 1. Darauf folgt das
Element eintrag. In diesem Fall interessiert uns aber nur, der dritte Eintrag. (Datensatz)
Das Element name kommt vermutlich ohnehin nur einmal pro Eintrag vor. Wir wählen nur den
ersten. (Mit dem ersten Parameter haben wir übrigens die Suche eingeschränkt, damit nicht die
folgenden 3 Millionen Einträge auch noch durchsucht werden.) Mit to kann ein Bereich angegeben werden, z.B. 3 to 7 liefert die Einträge 3 bis 7. Auch Gruppierungen sind möglich: {3,8,12} sucht demnach im dritten, achten, und zwölften Adresseintrag nach dem Namen. Der Stern * steht wie gewohnt für einen Joker. Hier ist jeder Wert möglich. Die geschweifte Klammmer muss hier übrigens gesetzt werden. Der Doppelpunkt mit abgetrennter Zahl dient dazu, Textabschnitte in gemischten Elementen zu finden, wie man sie besonders von (X)HTML her kennt. <p>Ein <b>großes</b> Haus</p> enthält zum Beispiel zwei Textteile innerhalb der p-Tags, die von einem b-Element getrennt werden. Mit get_data(0, "p", "",":2") wäre es möglich, alle zweiten Text-Abschnitte eines beliebigen p-Elements ausfindig zu machen. Natürlich ist auch eine genauere Zähl-Pfadangabe vor dem Doppelpunkt möglich. |
Nachdem wir nun die Bedeutung der Suchparameter kennen, sollte es keine schwierige Aufgabe
sein, einen zweiten Test zu machen, der auch die übrigen drei Parameter zum Einsatz kommen lässt.
Diesmal begnügen wir uns aber nicht mit einer einzigen Abfrage, sondern führen gleich
drei Abfragen auf einmal durch.
<?php
require_once("../xml-line.php");
$mylines = new xml_line("xml-files/obst.xml");
//Abfrage 1 (bekommt Index [0])
//Alles finden, was den String "Him" enthält
$mylines->get_data(1,"","Him");
//Abfrage 2 (bekommt Index [1])
//Genau ein bestimmtes Obst-Element finden
//nahrungsmittel[1]/vegetarisch[1]/obst[2]
$mylines->get_data(1,"nahrungsmittel/vegetarisch/obst","","","1-1-2");
//Abfrage 3 (bekommt Index [2])
//Welches Obst hat einen guten Preis?
$mylines->get_data(1,"gemuese","",array("preis" => "gut"));
$result = $mylines->xml_stream();
?>
Mit der Ergebnisabfrage machen wir es uns einfach, indem wir davon ausgehen, dass tatsächlich etwas gefunden wird. Normalerweise müssen wir natürlich prüfen, ober ein Wert vorhanden ist, bevor wir ihn ausgeben. Außerdem begnügen wir uns der Übersicht halber mit einem Treffer je Abfrage und haben deshalb den ersten Parameter auf 1 gesetzt.
<?php
printf("<p>Welcher Eintrag enthält <i>Him</i>?<br>
Ergebnis von Suche 1 ist <b>%s</b>.</p>",
$result[0][0][0]);
printf("<p>Welchen Wert hat das Element
<i>nahrungsmittel[1]/vegetarisch[1]/obst[2]</i>?<br>
Ergebnis von Suche 2 ist <b>%s</b>.</p>",
$result[1][0][0]);
printf("<p>Welches Gemüse hat einen guten Preis (preis="gut")?
<br>Ergebnis von Suche 3 ist <b>%s</b>.</p>",
$result[2][0][0]);
?>
Wir erhalten folgende Ausgabe:
Welcher Eintrag enthält Him?
Ergebnis von Suche 1 ist Himbeere.
Welchen Wert hat das Element
nahrungsmittel[1]/vegetarisch[1]/obst[2]?
Ergebnis von Suche 2 ist Birne.
Welches Gemüse hat einen guten Preis (preis="gut")?
Ergebnis von Suche 3 ist Möhre.
Dass die Variable $result nicht nur einen einfachen Wert zurückgibt, wird bei diesem
Beispiel offenkundig.
Wie beim letzten Beispiel zu sehen war, nummeriert der erste Index einfach nur die
Abfragen, wobei mit 0 begonnen wird. Es ist nichts Ungewöhnliches und häufig Absicht, dass mehrere Treffer gelandet
werden. Diese Ergebnisse zählt der zweite Index durch.
Der dritte Index beinhaltet mehrere Aspekte des Ergebnisses. Das Wichtigste ist häufig der
Inhalt des Elements, dem deshalb der Index [0] vorbehalten ist.
Die Tabelle gibt Aufschluss über die weitere Belegung.
index | Bedeutung | Format | Beispielwert | Anmerkungen |
---|---|---|---|---|
0 | Elementwert | String | ein Sack Zement | Gibt den Wert eines Elements wieder, also das, was zwischen den Tags steht. Dies kann auch Whitspace sein. (Die Rückgabe von Whitspace lässt sich momentan noch nicht durch eine Methode unterdrücken. Sie müssen daher selbst entscheiden, wie Sie mit Leerzeichen, Tabulatoren und Zeilenumbrüchen umgehen.) |
1 | Elementname | String | obst | Manchmal ist es nützlich zu wissen, wie das Element heißt, dessen Wert man kennt. In diesem Beispiel könnten Sie z.B. festellen, ob der Apfel in die Kategorie Obst oder Gemüse gehört. |
2 | Attribut-Array | Array | [preis] => gut | Ein Attribut-Array wird bei dieser Ergebnisform immer mitgeliefert. Wenn es leer ist, hat das Element keine Attribute. Ansonsten werden die Attribute als key-value-Paare gespeichert. |
3 | Elementpfad | String | nahrungsmittel/vegetarisch/obst | Hier gibt es jetzt den vollständigen Pfad. Zusammen mit dem Zählpfad (nächster Index) hat man dann alle notwendigen Angaben, um z.B. bei der unscharfen Suche in einem Dokument, genaue Zielkoordinaten für eine Operation im zweiten Durchgang zu gewinnen. (Genauere Beispiele folgen später.) |
Um unser Ergebnisarray in Aktion zu sehen, bauen wir die Testabfrage etwas um. Wir heben die Beschränkung für die Rückgabe auf, so dass auch mehrere Ergebnise pro Abfrage möglich sind, dadurch erhalten wir für die zweite Abfrage mit Index[1] zwei Werte.
<?php
require_once("../xml-line.php");
$mylines = new xml_line("xml-files/obst.xml");
//Abfragen:
//Index [0]
$mylines->get_data(0,"","Him");
//Index [1]
$mylines->get_data(0,"nahrungsmittel/vegetarisch/obst","","","1-1-{1,2}");
//Index [2]
$mylines->get_data(0,"gemuese","",array("preis" => "gut"));
$result = $mylines->xml_stream();
echo "<pre>";
print_r($result);
echo "</pre>";
?>
In der Ausgabe lassen wir uns das gesamte Ergebnis-Array mit der print_r()-Funktion anzeigen, wie auch im PHP-Quelltext (oben) zu sehen ist.
Array ( [1] => Array ( [0] => Array ( [0] => Apfel [1] => obst [2] => Array ( ) [3] => nahrungsmittel/vegetarisch/obst [4] => 1-1-1 ) [1] => Array ( [0] => Birne [1] => obst [2] => Array ( ) [3] => nahrungsmittel/vegetarisch/obst [4] => 1-1-2 ) ) [0] => Array ( [0] => Array ( [0] => Himbeere [1] => obst [2] => Array ( ) [3] => nahrungsmittel/vegetarisch/obst [4] => 1-1-3 ) ) [2] => Array ( [0] => Array ( [0] => Möhre [1] => gemuese [2] => Array ( [preis] => gut ) [3] => nahrungsmittel/vegetarisch/gemuese [4] => 1-1-1 ) ) )
Wie leicht zu erkennen ist, stimmt die Reihenfolge der ersten Indizes nicht. Das liegt daran, dass jeder Abfrage ihre Ergebnisse so ins Rückgabe-Array einträgt, wie sie gefunden werden. Für die Auswertung spielt es jedoch keine Rolle. Das Abgreifen der einzelnen Ergebnisse lässt sich problemlos mit ein paar Zeilen Skript erschlagen.
Wenn Sie eine Weile mit der get_data()-Methode experimentiert haben, werden Sie vielleicht schnell den Wunsch haben, nicht nur Werte zu lesen, sondern auch Änderungen durchzuführen oder Daten und Elemente zu löschen. Auch der Umgang mit Attributen und deren Werten wird später noch eingehend erklärt.
Auch diesen Teil des Tutorials wollen wir mit einem vollständigen Beispiel beginnen.
Dafür rufen wir uns aber noch einmal kurz die Syntax für das Auffinden von Elementen
für die Methode get_data() ins Gedächtnis:
$mylines->get_data([[[[[[Trefferzahl], Element(pfad)], Suchstring ], Attribut-Array(name1=>value1, name2=>value2, ... )], Zählpfad]);
Die Reihenfolge der Parameter wurde auch für die Änderungsmethoden beibehalten, mit dem Unterschied, dass diese meist in einem Array übergeben werden. Der zweite Parameter enthält dann den Wert, der geändert werden soll:
$search = array($treffer, $elementpfad, $teilstring, $attributarray, $zaehlpfad); $mylines->change_data($arg, $value);
Anders als bei get_data() erhalten wir bei change_data() kein Ergebnisarray. (Im Moment gibt es auch noch keine Möglichkeit festzustellen, ob der Ersetzungsvorgang erfolgreich war. Gedacht ist für folgende Versionen daran, die Zahl der Ersetzungen als Ergebnis zurückzuliefern.) Um etwas von den Änderungen zu haben, müssen wir die Änderungen entweder in eine Datei schreiben oder in einer Variablen speichern.
$mylines = new xml_line("obst.xml", // infile, "xml" // outformat "obst-out.xml"); //outfile
Wie wir von unserem Beispiel mit get_data() wissen, ist nur der erste Parameter
zwingend erforderlich. Bei Änderungen brauchen wir aber auch ein Ausgabeformat. Das ist
normalerweise "xml". Dabei bleibt die Formatierung im Idealfall so erhalten, wie sie
vorher war. (Leere Elemente werden allerdings mit Start- und Endtag ausgegeben auch wenn
sie vorher kombiniert waren.)
Für die Darstellung von XML-Code auf einer HTML-Seite, habe ich eine Highlight-Funktion
integriert. Um mit XML-Line zu experimentieren,
ist es einfacher, diese Funktion zu nutzen, als ständig die Ausgabedatei zu öffnen.
Wird der dritte Parameter weggelassen, wird die Ausgabe nicht in eine Datei sondern automatisch
in einen Puffer geschrieben. Dieser kann am Ende mit der Methode get_output() angezeigt werden.
(Wer beobachten will, wie der Parser intern arbeitet, kann testweise mal mit "csv" als Outputformat
experimentieren. Dies ist vielleicht nützlich für Entwickler, die an der Klasse selbst
Änderungen vornehmen wollen.)
Um die Änderung von Werten jetzt auszuprobieren, machen wir aus dem ersten obst-Element eine Zitrone und aus dem Schnitzel ein Würstchen.
<?php
require_once("../xml-line.php");
//Ausgabeformat HTML (Highlight-XML)
$mylines = new xml_line("obst.xml", "hixml");
//Änderungsabfrage Index [0]
$arg=array(0,"obst","","","1-1-1");
$mylines->change_data($arg, "Zitrone");
//Änderungsabfrage Index [1]
$arg=array(0,"","Schnitzel");
$mylines->change_data($arg, "Würstchen");
$mylines->xml_stream();
// Inhalt de Puffers ausgeben:
echo $mylines->get_output();
?>
Und so sieht das Ergebnis aus:
Um eine normale XML-Ausgabedatei zu erzeugen, schreiben Sie einfach, wie bereits oben
gezeigt:
$mylines = new xml_line("obst.xml", "xml", "obst-out.xml");
Vergessen Sie bitte nicht, vorher die Schreibrechte entsprechend zu setzen, damit die
Datei angelegt werden kann. Ein Überschreiben der Eingabedatei ist übrigens erst
hinterher möglich, weil gleichzeitig eine Datei zum Lesen und eine zum Schreiben geöffnet wird.
Da die Verarbeitung sequentiell erfolgt, können dadurch auch sehr große Dateien
abgearbeitet werden. Soll die Ausgabedatei die Quelldatei ersetzen, können Sie das mit den
üblichen Dateifunktionen in PHP erledigen. Häufig möchte man aber vielleicht die Datei
erst prüfen (z.B. in einem CMS), bevor man die Ursprungsdatei ersetzt.
Die folgende Tabelle gibt Aufschluss über die Aufgabe der einzelnene Parameter. (Der Prameter $arg beinhaltet immer das oben beschriebene Array, dass bis zu 5 Elemente enthalten kann.)
Methode | Erläuterungen |
---|---|
change_data($arg, $replace) | Ändert den gefundenen Wert oder die Werte. Zum Löschen ersetzen Sie einfach mit einem Leerstring: change_data($arg, ""). Achtung: Es werden keine im Element enthaltenen Elemente geändert oder gelöscht sondern nur nackter Text! soll der gesamte Inhalt gelöscht werden, verwenden Sie delete_content() oder replace_content(). (Siehe auch die Erläuterungen dort.) |
append_data($arg, $replace) | Wie change_data($arg, "") mit dem Unterschied, dass der neue String an den alten angehängt wird. |
delete_content($limit, $elementpath, "", $attr_arr, $countpath) | Diese Methode löscht den gesamten Inhalt der zwischen den Tags des gesuchten Elements steht. Achtung: Die Abhängigkeit der Aktion von einem enthaltenen Suchwort ist hier nicht möglich, weil der Löschvorgang schon beginnen muss, bevor alle enthaltenen Werte bekannt sind. Braucht man eine solche Bedingung, muss die Datei zweimal geparst werden: Suchen mit get_data() und Verwendung des Ergebnisses für delete_content(). |
replace_content($arg, $replace) | Für diese Methode gilt das gleiche, wie für delete_content(). Zusätzlich wird ein Ersetzungsstring übergeben. Dieser kann auch XML-Code enthalten, was einen einfachen Umbau des Dokuments erlaubt. |
delete_element($limit, $elementpath, "", $attr_arr, $countpath) | Ähnlich wie replace_content() (s.o.), nur wird hier das gesamte Element, inkl. Start- und Endtag, entfernt. |
replace_element($arg, $replace) | Ähnlich wie replace_content() (s.o.), jedoch wird das gesamte Element entfernt. |
insert_element($arg, $insert) | Mit dieser Methode fügen Sie Text oder XML-Code direkt hinter dem Start-Tag ein. Auch hier kann kein String als Bedingung (3. Parameter) mitgegeben werden. |
insert_before_end ($arg, $insert) | Wie insert_element() nur erfolgt die Einfügung vor dem Endtag. |
insert_after_element($arg, $insert) | Mit dieser Methode fügen Sie Text oder XML-Code direkt hinter dem End-Tag des gesuchten Elements ein. (Der Methodenname insert_element_after_element wurde aus logischen Gründen geändert. Der Bug der vorigen Versionen wurde beseitigt.) |
Im Verzeichnis examples im Downloadpaket finden Sie verschiedene Beispiel, auch zu oben gezeigten Methoden. Diese Dateien können Sie als Ausgansbasis für eigene Experimente verwenden. Das Ergänzungsverzeichnis für Version 0.3 zeigt auch neue Methoden, die hier noch nicht dokumentiert sind.
Für die Arbeit mit Attributen gibt es einige eigene Funktionen.
Die Parameter für die Attributabfrage sind nicht völlig identisch
mit den für die Elementabfrage verwendeten Parameter. Unterschiede
sind markiert:
$mylines->get_attribute($limit, //Maximale Trefferzahl (wie bei Elementen) $path, //Element oder Elementpfad (wie bei Elementen) $attrvalue, //Wert des Attributs. - Vollständiger String! $attrn, //Name des Attributs. - Kein Array! $elcount);//Element-Zählpfad (wie bei Elementen)
Die Parameter sind auch hier alle optional. Bei den Attribut-Methoden mit Änderungsparameter, werden die Suchparameter wie bei den für Elementsuche bekannten Beispiele in einem Array zusammengefasst, dass wir hier $arg nennen wollen.
Grenzen der Attributmethode:
Das Ergebnis wird genauso abgefragt, wie für get_data() beschrieben. Das Ergebnisarray sieht allerdings etwas anders aus. Unterschiede sind markiert:
Array ( [0] => Array //Funktionsindex, bei nur einer Abfrage immer 0 ( [0] => Array // Index für gefundene Treffer ( [0] => gut //Wert des Attributs [1] => gemuese //Name des Elements [2] => preis //Name des Attributs //(kein Array) [3] => nahrungsmittel/vegetarisch/gemuese //Elementpfad [4] => 1-1-1 //Elementzählpfad ) ) )
Wie man sieht, enthält das Ergebnisarray wie bei den Element-Methoden Informationen, die auch noch für weitere Aktionen verwendet werden können.
Natürlich gibt es auch bei den Attributen die Möglichkeiten zum Löschen und Ändern von Namen und Werten.
Methode | Erläuterungen |
---|---|
$mylines->delete_attribute(0, $path, $attrvalue, $attrn, $elcount); | Löscht das gesamte Attribut (Name und Wert). |
$mylines->replace_attribute($arg, array("neuname"=>"neuwert")); | Ersetzt ein gesuchtes Attribut durch ein anderes name-value-Paar. |
$mylines->change_attribute_value($arg, $value); | Ersetzt nur den Wert eines Attributs, wenn die Suchbedingung stimmt. |
Will man ein oder mehrere Attribute zum Element hinzufügen, wird intern die Elementsuchfunktion genutzt. Daher können auch den Elementen Attribute hinzugefügt werden, die noch keine anderen Attribute haben. Die Parameterliste für die Elementsuche ist also fast die selbe wie z.B. bei get_element(). Da die Funktion aber schon beim Starttag einsetzt, kann der dritte Parameter, Suchtext im Element, nicht genutzt werden! (Sollte man in die Verlegenheit kommen, das Einfügen von Attributen vom vorhanden Elementinhalt abhängig zu machen, muss man leider mit zwei Durchgängen arbeiten. Diese Einschränkung kennen wir ja bereits von anderen Methoden.
Syntax:
$search_array= array(0, $path, "", $attr_array, $elcount); $insert_array= array("name1"=>"wert1", "name2"=>"wert2", "name3"=>"wert3"); //usw. $mylines->add_attributes($search_array, $insert_array);
Code-Beispiel
[...]
$search_array = array(0, "obst", "", "","1-1-1");
$insert_array = array("geschmack"=>"lecker", "farbe"=>"grün");
$mylines->add_attributes($search_array, $insert_array);
$mylines->xml_stream();
[...]
Hier werden dem ersten obst-Element zwei Attribute hinzugefügt. Das vollständige Beispiel
finden Sie im Downloadpaket im Verzeichnis examples
Häufig haben XML-Elemente ein einmaliges Identifikations-Attribut: id="[nummer]"
Ein solches Merkmal erleichtert den Zugriff auf ein Element. Daher enthält XML-Line auch einige
Abkürzungsmethoden, die den Zugriff weiter vereinfachen:
Methode | Erläuterungen |
---|---|
find_data_by_id( string $value[, string $idname]) | Mit diesr Methode kann direkt der Wert eines Elements gefunden werden, dessen Attribut den Namen "id" hat. Der erste Parameter enthält den Wert von "id". Wird ein zweiter Parameter angegeben, steht dieser anstelle von "id". Beispiel: find_data_by_id("133", "nr") findet z.B. <datensatz nr="133">. |
change_data_by_id( string $value, string $replace[, string $idname ]) | Das gleiche mit der Möglichkeit zur Änderung des gefundenen Wertes. Auch hier kann optional ein Parameter übergeben werden, der den Default-Attributnamen "id" überschreibt. |
Die vorgestellten Methoden sind ein Beleg dafür, dass für spezielle Aufgaben auch Methoden geschrieben werden, die
Diese Methode ist besonders dazu gedacht, einen schnellen Zugriff auf XML-Dateien zu erhalten, die im Grunde flache Tabellen sind, und eventuell sogar nichts anderes als ein XML-Export aus einer Datenbanktabelle oder Tabellenkalkulation sind.
Dieses Beispiel macht es sich etwas schwerer, da auch Attribute und sogar ein Element mit untergeordneten Elementen enthalten sind.
Aufgabe: Alle Datensätze aus der Datei adressen.xml einlesen, die mit dem Tag eintrag eingeschlossen sind.
<?php
require_once("../xml-line.php");
$mylines = new xml_line("xml-files/adressen.xml", "hixml");
$mylines->get_record(0,"eintrag");
$mylines->xml_stream();
print $mylines->get_output();
?>
Ergebnis-Array:
<?php
echo "<pre>";
print_r($mylines->table_result);
echo "</pre>";
?>
Array ( [0] => Array ( [0] => Array ( [name] => Klausmann [vorname] => Heinz [anschrift/strasse] => Feldstrasse 5 [anschrift/strasse@info] => 3 x klingeln! [anschrift/plz] => 23456 [anschrift/ort] => Teststadt ) [1] => Array ( [name] => Meyer [vorname] => Guste [anschrift/strasse] => Tannhäuserweg 12 [anschrift/plz] => 98765 [anschrift/ort] => Nulldorf ) [2] => Array ( [name] => Katzbeck [vorname] => Karl-Heinz [anschrift/strasse] => An der Teststrecke 123a [anschrift/plz] => 63555 [anschrift/ort] => Netzbach ) ) )
Besonderheit: Die Zuordung von Attributen geschieht folgendermaßen:
['eintrag@datum']
Enthält ein Element des Datensatzes ein weiteres Element, wird dies
folgendermaßen in die Tabellenstruktur eingegliedert:
['anschrift/strasse']
Die get-record-Methode hat natürlich ihre Grenzen und eignet sich vor allem für Tabellen- oder Datenbankexporte. Wie in einer Datenbanktabelle muss jede Spalte einen anderen Namen haben. Würde hier ein gleichnamiges Element auftauchen, würde der vorige Wert überschrieben werden.
Aufgabe: Welchen Wert hat das Element name im zweiten Datensatz? Das Ergebnis-Array steckt in der Variablen table_result.
<?php
printf("<p>Der Wert ist: <b>%s</b></p>",
$mylines->table_result[0][1]['name']);
?>
Der Wert ist: Meyer
Noch einmal zur Erinnerung: Der erste Index zählt die aufgerufenen Methoden. In diesem Beispiel gibt es nur die eine, also [0]. Der Index [1] ist das zweite zurückgelieferte Ergebnis, da wir auch hier bei 0 anfangen zu zählen.
Diese Klasse ist nicht zuletzt für die Möglichkeit entwickelt worden, direkt auf XHTML-Dokumente zugreifen zu können, die ja gültige XML-Dokumente sind. Dort wird man häufig den Fall finden, dass Elemente nicht nur andere Elemente oder Werte enthalten sondern das Werte und Elemente nebeneinander stehen und sich abwechseln können. Das folgende Beispiel ist natürlich kein vollwertiges XHTML-Dokument, zeigt aber das Problem.
<?php
$mylines = new xml_line("xml-files/mixed-content1.xml");
$mylines->get_data(0, "p");
$result=$mylines->xml_stream();
echo "<pre>";
print_r($result);
echo "</pre>";
?>
Inhalt von p auslesen:
Array ( [0] => Array ( [0] => Array ( [0] => Herr Müller hatte am [1] => p [2] => Array ( ) [3] => html/p [4] => 1-1 ) [1] => Array ( [0] => Bauchschmerzen. [1] => p [2] => Array ( ) [3] => html/p [4] => 1-1 ) ) )
Wir erhalten zwei Werte für p. Das Element enthält zwei Textknoten und ein weiteres untergeordnetes Element mit eigenem Inhalt.
Lösungsweg: Wir müssen auf den zweiten Textknoten innerhalb des p-Elements zugreifen und diesen ersetzen:
<?php
$mylines = new xml_line("xml-files/mixed-content1.xml", "hixml");
$arg=array(0, "p", "", "","1-1:2");
$replace= " Zahnschmerzen";
$mylines->change_data($arg,$replace);
$mylines->xml_stream();
echo $mylines->get_output();
?>
Keine Frage, dass man dieses Problem mit einer str_replace-Funktion schneller erschlagen hätte, aber es gibt sicherlich Aufgabenstellungen, in denen man sich über die Möglichkeiten des gezielten Zugriffs auf bestimmte Textknoten freut.
Wegen seiner XHTML-Tauglichkeit bietet sich XML-Line auch als Werkzeug für kleine CMS-Lösungen an. Je nach Anspruch kann dabei der Umweg über XML/XSLT oder Templates entfallen, indem man direkt auf die XHTML-Datei zugreift, eine veränderte Vorschaudatei generiert und diese nach Prüfung an die Stelle der Originaldatei setzt.
Ein Beispiel mit einer fingierten Nachrichtenseite finden Sie als xhtml-test.php im Verzeichnis examples im Downloadpaket. (Quelldatei: examples/xml-files/xhtml-test.html). Ausgegeben wird sie als outxhtml.html im Verzeichnis examples/output.
Es würde zu weit führen, das Beispiel hier komplett zu erläutern. Für Fortgeschrittene
PHP-Programmierer sollte es keine große Kunst sein, sich im Quelltext zurecht zu finden.
Hier nur der Vorgang im Groben:
Die untergeordneten Element von body werden zunächst eingelesen.
$mylines->get_data(0,"html/body/*");
Mit Hilfe der Ergebnisse im $result-Array wird dann ein Formular gebaut, dass alle
Elementinhalte editierbar macht.
Die geänderten Werte werden dann wieder an das Skript geschickt, das nun die Änderungsmethoden
in einer Schleife ausgibt und anschließend die Änderungen durchführt:
<?php
require_once("../xml-line.php");
if (count($_POST) and isset($_POST['check'])) {
$mylines = new xml_line("xml-files/xhtml-test.html",
"xml",
"output/outxhtml.html");
foreach ($_POST['check'] as $k => $v) {
list($el, $z) = split(',',$v);
$w = $_POST['wert'][$k];
$mylines->change_data(array(0,$el,"","",$z), $w);
}
$mylines->xml_stream();
}
?>
Durch den ersten Parsevorgang sind alle Element- und Zählpfade bekannt. Dadurch ist eine präzise Ansteuerung der Elementwerte im zweiten Durchgang möglich.
Der Vorgang wird Ihnen sicherlich klarer, wenn Sie sich das Beispiel direkt ansehen und damit experimentieren. Bei einiger Beschäftigung mit XML-Line sollten Sie auch in der Lage sein, dieses Beispiel so zu ändern, dass Nachrichten ganz gelöscht und weitere Nachrichten eingefügt werden können.
Sehr häufig kommt es vor, dass nur Kleinigkeiten in einer Webseite geändert werden sollen. Möglichkeiten für solche Aufgabenstellungen lassen sich mit XML-line im Handumdrehen realisieren.
Auch wenn sich mit XML-Line viele Aufgaben im Bereich XML und speziell auch bei der Arbeit mit XHTML bewältigen lassen, soll nicht der Eindruck entstehen, dass es sich bei dieser Klasse bereits um ein vollkommen ausgereiftes Werkzeug handelt. Wer es einsetzt, sollte genau prüfen, ob es auch das macht, was es soll. Für die Tauglichkeit der Klasse technische und wirtschaftliche Folgen wird ausdrücklich keine Garantie übernommen. Das gleiche gilt für diese Einführung, die sicherlich noch einige Verbesserungen erfahren wird. Sachliche Kritik und Anregungen und Rückmeldungen (= Feedback ;-)) sind stets willkommen. Bitte verwenden Sie dafür mein Kontaktformular.