Felix Riesterer: Parserproblem, oder Denkfehler?

Beitrag lesen

Lieber Christoph,

das Datumsformat reicht völlig in der Form (yyyy.mm.dd), sodass dann per locale die jeweilige Form generiert werden kann (oder gleich ein unix-Zeitstempel). Da bin ich für Vorschläge offen. Aber man sollte die kirche im Dorf lassen...

Zu Deinem "unclosed token" Problem:
Bitte vollstaendige Fehlermeldung

XML error: not well-formed (invalid token) at line xxx

Bitte genuegend Daten zum Nachvollziehen

Kommt gleich weiter unten!

Bitte die Namen und Versionen aller Beteiligten (hier reichen wohl PHP und XML-Parser)

Also auf meinem Win32-Apache2.0.52 sagt phpinfo():

  • php-Version 4.3.10
  • XML
      - XML Support                 active
      - XML Namespace Support       active
      - EXPAT Version               1.95.6
  • xmlrpc
      - core library version        xmlrpc-epi v. 0.51
      - php extension version       0.51
      - author                      Dan Libby

Hoffentlich war jetzt das von Dir Verlangte auch dabei...

Die GB-XML-Datei (wesentlicher Auszug):

<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>  
<!DOCTYPE gaestebuch [  
  <!ELEMENT gaestebuch (eintrag)+>  
  <!-- definiert das Grundgerüst des Dateiformates -->  
  
  <!ENTITY und "&#38;">  
  <!-- "und"-Zeichen (Ampersand) -->  
  <!ENTITY zeilenumbruch "&#10;&#13;">  
  <!-- "Zeilenumbruch" Windows-kompatibel -->  
  
  <!ELEMENT eintrag (autor, nachricht)>  
  <!-- definiert den Aufbau eines GB-Eintrags -->  
  <!ATTLIST eintrag  
  datum  CDATA #REQUIRED  
  zeit  CDATA #REQUIRED  
  >  
  
  <!ELEMENT autor (#PCDATA)>  
  <!-- definiert den Aufbau der Daten über den Autor eines Eintrags -->  
  <!ATTLIST autor  
  email  CDATA #IMPLIED  
  homepage  CDATA #IMPLIED  
  icq   CDATA #IMPLIED  
  aim   CDATA #IMPLIED  
  yim   CDATA #IMPLIED  
  msn   CDATA #IMPLIED  
  >  
  <!-- Die Zusatzdaten zum Autor werden in diesen Attributen gespeichert -->  
  
  <!ELEMENT nachricht (#PCDATA)>  
  <!-- definiert den Aufbau der Daten für die Nachricht -->  
]>  
<gaestebuch>  
 <eintrag datum="28.04.2005" zeit="20:20">  
  <autor email="" homepage="">Susi</autor>  
  <nachricht>SO&zeilenumbruch;wollt nur nochmal die Caro grüßen!!!&zeilenumbruch;Kommt Philipp&und;Tanja morgen mit?</nachricht>  
 </eintrag>  
</gaestebuch>

Die unclosed Entity befindet sich in der Zeile <nachricht></nachricht> und bezieht sich auf das &und;. Anscheinend wird beim Parsen die Entity in ihren Wert umgewandelt, sodass nur noch ein &#38; (also das Ampersand) übrigbleibt, was er zurecht bemeckert. Aber wenn der Parse-Vorgang verschachtelt abläuft, warum wandelt er die Entities nicht erst ganz zum Schluss um??? Außerdem bekomme ich nur noch den Reststring nach der letzten Entity geliefert. :-(

Das erzeugte Array (bei geändertem Ampersand-Wert auf &#37;!!) dieser Daten sieht so aus:

Array  
(  
    [0] => Array  
        (  
            [name] => EINTRAG  
            [attributes] => Array  
                (  
                    [DATUM] => 28.04.2005  
                    [ZEIT] => 20:20  
                )  
  
            [child] => Array  
                (  
                    [0] => Array  
                        (  
                            [name] => AUTOR  
                            [attributes] => Array  
                                (  
                                    [EMAIL] =>  
                                    [HOMEPAGE] =>  
                                )  
  
                            [content] => Susi  
                        )  
  
                    [1] => Array  
                        (  
                            [name] => NACHRICHT  
                            [content] => Tanja morgen mit?  
                        )  
  
                )  
  
        )  
  
)

Auf php.net hatte ich mir für diese Umwandlung folgende Klasse "mitgenommen", da ich das selbst noch nicht selbst hinbekomme:

class XMLParser  
   {  
   var $filename;  
   var $xml;  
   var $data;  
  
   function XMLParser($xml_file)  
      {  
      $this->filename = $xml_file;  
      $this->xml = xml_parser_create();  
      xml_set_object($this->xml, $this);  
      xml_set_element_handler($this->xml, 'startHandler', 'endHandler');  
      xml_set_character_data_handler($this->xml, 'dataHandler');  
      $this->parse($xml_file);  
      }  
  
   function parse($xml_file)  
      {  
      if(!($fp = fopen($xml_file, 'rb+')))  
         {  
         die('Cannot open XML data file: '.$xml_file);  
         return false;  
         }  
  
      $bytes_to_parse = 65536;  
  
      while ($data = fread($fp, $bytes_to_parse))  
         {  
         $parse = xml_parse($this->xml, $data, feof($fp));  
  
         if (!$parse)  
            {  
            die(  
                sprintf("XML error: %s at line %d",  
                xml_error_string(xml_get_error_code($this->xml)),  
                xml_get_current_line_number($this->xml)));  
                xml_parser_free($this->xml  
                );  
            }  
         }  
  
      return true;  
      }  
  
   function startHandler($parser, $name, $attributes)  
      {  
      $data['name'] = $name;  
      if ($attributes) $data['attributes'] = $attributes;  
      $this->data[] = $data;  
      }  
  
   function dataHandler($parser, $data)  
      {  
      if($data = trim($data))  
         {  
         $index = count($this->data) - 1;  
         $this->data[$index]['content'] = $data;  
         }  
      }  
  
   function endHandler($parser, $name)  
      {  
      if (count($this->data) > 1)  
         {  
         $data = array_pop($this->data);  
         $index = count($this->data) - 1;  
         $this->data[$index]['child'][] = $data;  
         }  
      }  
   }  
  
// XML-Daten in ein Array umwandeln  
$daten = new XMLParser($datendatei);  
$daten = $daten->data[0];

Diese Klasse ist nicht von mir. Ich verstehe sie auch nicht wirklich, da ich in PHP das Objektorientierte noch nicht kann. Aber anscheinend ist sie nicht optimal, denn sie gibt mir die Zeile Nachricht erst nach dem &und; aus... nachdem ich in der DTD den Wert verändert habe. *grr*

Für eine bessere Parser-Klasse bin ich ebenso dankbar, wie für Hinweise, die Denkfehler von mir aufzeigen.

Liebe Grüße aus Ellwangen,

Felix Riesterer.