molily: XML Parse problem

Beitrag lesen

Hallo,

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<news>
 <story id="1">Hallo1</story>
 <story id="2">Hallo2</story>
</news>

Jetzt liesse sich die Story zu einer ID über XML-DOM sehr, sehr
einfach auslesen:

So einfach ist es nicht, denn dass id ein Attribut vom Typ ID ist, muss aus der DTD hervorgehen, sonst findet get_element_by_id das Element nicht.

---pseudo-code--
my $story = $doc->get_element_by_id( $id )->child_nodes()->item(0)->node_value();

Das lässt sich übrigens einfacher mit get_content lösen. Zum Beispiel so:

$xml_file='news.xml';
$id='a1';
$dom = @domxml_open_file(realpath($xml_file), DOMXML_LOAD_PARSING, $error);
if ($dom and !$error) {
 $story_element = $dom->get_element_by_id($id);
 if ($story_element) {
  $story_text = $story_element->get_content();
  echo($story_text);
 } else {
  echo('<p>Die Story-ID '.$id.' konnte nicht gefunden werden.</p>');
  $story_text=false;
 }
 $dom->free();
} else {
 echo('<p>Fehler beim Einlesen/Verarbeiten des XML-Dokuments '.$xml_file.'.</p>');
 /* Im $error-Array werden Parsing-Fehler gespeichert */
 // if ($error) print_r($error);
}

Die Error-Behandlung bei DOMXML_LOAD_PARSING geht mit 4.3.4 nicht, mit 4.3.6 schon. Ausreichen würde natürlich $dom = @domxml_open_file(realpath($xml_file)); if ($dom) { ... }, nur dann lässt sich nicht unterscheiden, ob schon beim Parsen Fehler auftreten.

Dann gibt es noch einen weiteren Fallstrick: Wenn nicht gerade DOMXML_LOAD_VALIDATING als zweiter Parameter von domxml_open_file/_mem angegeben ist, muss die DTD im Dokument selbst enthalten sein, damit das Attribut id als ID-Attribut erkannt wird (siehe oben). Also:

<?xml ... ?>
<!DOCTYPE news [
<!ELEMENT news (story)+>
<!ELEMENT story (#PCDATA)>
<!ATTLIST story
 id ID #REQUIRED

]>
...

Mit DOMXML_LOAD_VALIDATING kann die Dokumenttyp-Deklaration auch <!DOCTYPE news SYSTEM "news.dtd"> lauten (bzw. bei domxml_open_mem ein absoluter Pfad), die DTD also eine externe Datei sein. Dabei wird aber das ganze Dokument gegen die DTD validiert (DOMXML_LOAD_PARSING findet nur Wohlgeformtheitsfehler), was man meistens nicht will und was unnötig Zeit kostet.

Vielleicht sollte man in solchen Fällen wirklich mit den expat-Funktionen arbeiten http://de3.php.net/manual/en/ref.xml.php, die laufen wahrscheinlich schneller als validierende domxml_open_*. Vor allem ist es bei solchen einfachen Dokumentstrukturen entsprechend einfach, den Textinhalt eines story-Elements mit einer bestimmten ID zu finden (im Start-Tag-Handler einen Flag setzen, wenn die gesuchte ID gefunden wird und im Character-Data-Handler den Elementinhalt speichern, wenn der Flag gesetzt ist).

Übrigens darf ein Attribut vom Typ ID nicht mit einer Zahl beginnen.

Mathias