Gestire XML in PHP: errore con una classe

Sto scrivendo una piccola classe che gestisce la lettura di file xml.

ora però ho un errore.

Ho seguito questo riferimento:

http://www.siforge.org/articles/2005/06/28-php-sax.html

la classe è in sintesi questa:

<?php

class parserXML {

   // costruttore
   function parserXML () {

      $struct = array();
      $this->struct = $struct;

   }

   // Funzioni di callback

   function startElement($parser, $name, $attrs) {
      // [...]
   }

   function data($parser, $data) {
      // [...]
   }

   function endElement($parser, $name) {
      // [...]
   }

   function parse_file($file) {

      $xml_parser = xml_parser_create();

      xml_set_element_handler($xml_parser, $this->startElement, $this->endElement);

      xml_set_character_data_handler($xml_parser, $this->data);

   /**/   $parse = xml_parse($xml_parser, file_get_contents($file));

      if(!$parse) {

         die("XML parsing error");

         xml_parser_free($xml_parser);

      }

      return $this->struct;

   }

}

?>

Ho omesso le cose non inerenti.

Ho dovuto trasformare alcuni elementi per farli interagire nella classe ma ricevo ancora questo errore:

Warning: xml_parse() [function.xml-parse]: Unable to call handler ()

il punto incriminato è quello segnato con *

alle righe precedenti l'asterisco ho dovuto trasformare delle costanti in vettori di oggetti per adeguare quelle che erano funzioni alla classe ( $this->startElement, $this->endElement erano "startElement" e "endElement").

Ma l'handler di cui fa mensione dovrebbe essere normalmente contenuto in $xml_parser.

Dov'è l'inghippo?

inviato 10 anni fa
arjuna
X 0 X

Quando PHP vuole un handler di funzione bisogna seguire questa regola: se si tratta di una comune funzione allora bisogna mettere il suo nome tra apici, come una stringa. Se invece si tratta di un metodo di una classe bisogna passare un array con 2 valori, l'oggetto ed il nome del metodo.

Nel tuo caso devi usare:

xml_set_element_handler($xml_parser, array($this,"startElement"), array($this,"endElement"));

 :bye:

risposto 10 anni fa
Gianni Tomasicchio
X 0 X

Come faccio a rendere globale un array?

$struct deve essere l'array dove vanno registrate le mie informazioni ma questa scrittura non funziona come vorrei:

<?php

class parserXML {

   // variabili Globali

   var $struct;

   // costruttore
   function parserXML () {

      $this->struct = array ();

   }

?Z>

Ottengo questo errore:

Warning: array_push(): First argument should be an array

il primo argomento è $this->struct

credo sia un oggetto, ma come faccio a rendere un array?

risposto 10 anni fa
arjuna
X 0 X

Non ho ben capito il tuo problema.  ???

Comunque, dov'è la funzione array_push() che ti da errore?

risposto 10 anni fa
Gianni Tomasicchio
X 0 X
<?php

function startElement($parser, $name, $attrs) {

      $tag = array("name"=>$name,"attrs"=>$attrs);

      $struct = $this->struct;

      array_push($struct, $tag);

   }
risposto 10 anni fa
arjuna
X 0 X

Come richiami i metodi dell'oggetto?

risposto 10 anni fa
Gianni Tomasicchio
X 0 X

Scusate se mi intrometto, cmq, se all'interno della funzione fai:

print_r($this->struct);

ti restituisce qualcosa?

Posta anche il pezzo di codice dove setti l'array...

PS cmq facendo così array_push, ti viene un array multidimensionale

Ex:

$arr1 = array("cap"=>"1234","piva"=>"234567");
$arr2 = array("nome"=>"pippo","attrs"=>"blablabla");
array_push($arr1,$arr2);

Ti restituirà:
Array ( [cap] => 1234 [piva] => 234567 [0] => Array ( [nome] => pippo [attrs] => blablabla ) )

Se volevi invece mantenere tutto in un array, forse ti conviene fare:

foreach($arr2 as $key=>$value)
 $arr1[$key] = $value;
print_r($arr1);

Restituirà:
Array ( [cap] => 1234 [piva] => 234567 [nome] => pippo [attrs] => blablabla )

(Se non volevi fare così, chiedo venia  :P )

ciao

risposto 10 anni fa
Lore
Lore
1
X 0 X

queste funzioni sono automatiche.

ora ti scrivo la procedura:

<?php

$album = 'foto'; // questo è ciò che cambia

$gallery = new gallery ("xmlData/".$album.".xml"); // il parametro che passo è il file .xml che contiene i dati da analizzare

$dati = $gallery->data; // $dati deve essere un array contenente la lettura del .xml

?>

ecco la classe:

<?php
include ("include/parserXMLClass.php"); // qui c'è l'analizzatore vero e proprio

class gallery extends parserXML {

   // variabili Globali

    var $fdata;  // sarebbe il file .xml che gli passo

   // costruttore
   function gallery ($fdata) {

      $this->data = $this->parse_file($fdata); // questa è l'azione principale, si trova nel file che includo, lo trovi sotto

   }
}
?>

ecco l'altra classe:

<?php

class parserXML {

   // variabili Globali

   var $struct; // questo è l'array dove verranno registrati i dati dell'.xml

   // costruttore
   function parserXML () {

      $this->struct = array ();

   }

   // Funzioni di callback

   function startElement($parser, $name, $attrs) {

      $tag = array("name"=>$name,"attrs"=>$attrs);

      $struct = $this->struct;

      array_push($struct, $tag);

   }

   function data($parser, $data) {

      if(trim($data)) {

         $this->struct[count($this->struct)-1]['data']=$data;

      }

   }

   function endElement($parser, $name) {

      $this->struct[count($this->struct)-2]['child'][] = $this->struct[count($this->struct)-1];

      $struct = $this->struct;

      array_pop($struct);

   }

   // Funzione che parsa il file passatogli nell'argomento e restituisce
   // una struttura ad albero oggetti-array contenente il documento

   function parse_file($file) {

      $xml_parser = xml_parser_create();

      xml_set_element_handler($xml_parser, array($this,"startElement"), array($this,"endElement"));

      xml_set_character_data_handler($xml_parser, array($this,"data"));

      $parse = xml_parse($xml_parser, file_get_contents($file));



      if(!$parse) {

         die("XML parsing error");

         xml_parser_free($xml_parser);

      }

      $struct = $this->struct;

      return $struct;

   }

} // end class

?>

Credo che non ci sia altro da allegare

risposto 10 anni fa
arjuna
X 0 X

Questo è il risultato di print_r

Array ( [-2] => Array ( [child] => Array ( [0] => ) ) ) Array ( [-2] => Array ( [child] => Array ( [0] => ) ) [-1] => Array ( [child] => Array ( [0] => ) ) ) Array ( [-2] => Array ( [child] => Array ( [0] => ) ) [-1] => Array ( [child] => Array ( [0] => ) ) [0] => Array ( [child] => Array ( [0] => ) ) )

l'array esiste ma è vuoto, la funzione dovrebbe popolarlo

risposto 10 anni fa
arjuna
X 0 X

Questo è il risultato di print_r

Array ( [-2] => Array ( [child] => Array ( [0] => ) ) ) Array ( [-2] => Array ( [child] => Array ( [0] => ) ) [-1] => Array ( [child] => Array ( [0] => ) ) ) Array ( [-2] => Array ( [child] => Array ( [0] => ) ) [-1] => Array ( [child] => Array ( [0] => ) ) [0] => Array ( [child] => Array ( [0] => ) ) )

l'array esiste ma è vuoto, la funzione dovrebbe popolarlo

risposto 10 anni fa
arjuna
X 0 X

Tu ora hai fatto

print_r($this->struct), giusto?

Nella tuo metodo ad un certo punto fai "un'assegnazione":

$struct = $this->struct;

e la variabile (array) $struct è quello che passi alla funzione array_push...

se fai :

function startElement($parser, $name, $attrs) {

      $tag = array("name"=>$name,"attrs"=>$attrs);
                 
                $struct = array() ;
      $struct = $this->struct;
                if(is_array($struct))
                      print_r($struct);
               else
                  die("Error: non è un array");

      array_push($struct, $tag);

   }

a questo punto dovrebbe stamparti la frase nel die(), poichè quest'errore:

Warning: array_push(): First argument should be an array

vuol dire appunto che come primo argomento non gli passi un'array...

Prova anche questa, giusto per avere la certezza che non sia un array...

Sinc non saprei cosa dirti altrimenti...

ciao

risposto 10 anni fa
Lore
Lore
1
X 0 X

dice appuntoche non è un array

risposto 10 anni fa
arjuna
X 0 X

Sinceramente non so cosa possa essere....magari il nome $struct utilizzato sia come variabile globale della classe che come variabile statica della funzione, ma non penso, perchè anche nelle altre funzioni ho visto che è utilizzato...

Prova a fare al posto di

$struct = $this->struct;

$struct2 = array();
foreach($this->struct as $key=>$value)
   $struct2[$key] = $value;

print_r($struct2);
   
array_push($struct2, $tag);

Altrimenti per quanto mi riguarda, ho finito le idee ... :giveup:

( sarà anche colpa del venerdì  :P)

risposto 10 anni fa
Lore
Lore
1
X 0 X

mi serve usare $struct perchè ogni funzione lo manipola in un modo... per questo è globale.

risposto 10 anni fa
arjuna
X 0 X
mi serve usare $struct perchè ogni funzione lo manipola in un modo... per questo è globale.

ok, allora prova a fare come ti ho detto sopra, al posto di struct2 metti struct:

$struct = array();
foreach($this->struct as $key=>$value)   
$struct[$key] = $value;

print_r($struct);
array_push($struct, $tag)

( se nn ho capito male....)

risposto 10 anni fa
Lore
Lore
1
X 0 X

è un array multi mutli dimensionale, cred che non funzionerebbe...

ma il punto è che vorrei capire come usarlo coem array anche perchè non credo sia una cosa isolata, penso sia un passo importante questo

risposto 10 anni fa
arjuna
X 0 X

Dovrebbe funzionare lo stesso,ho fatto una prova veloce:

$struct = array(1=>array("a"=>"sdsdsd","b"=>array(1,2,3)),
      2=>array("a"=>"sdsdsd","b"=>array(1,2,3)),
      3=>array("a"=>"sdsdsd","b"=>array(1,2,3)));
   
   

foreach($struct as $key=>$value)
{
   $struct2[$key] = $value;
}
print_r($struct);
echo "<br>";
print_r($struct2);

Ed il risultato è lo stesso...

CMQ se non vuoi adottare questa soluzione, fai un po' di debug, non so coas consigliarti altrimenti....sorry  :'(

ciao

risposto 10 anni fa
Lore
Lore
1
X 0 X

array push serve ad aggiungere un nuovo elemento all'array generale

questo è il motivo per cui non posso fare diversamente

qualsiasi soluzione temporanea non ha senso una volta che $struct deve tornare disponibile fuori della funzione che lo ha invocato e alimentato...

non ho le conoscenze giuste per fare questo ma la cosa più triste per me è che non posso nemmeno LFM (leggere il fo***to manuale) perchè non so dove andare a sbattere...

che cos'è un oggetto? perchè quella funzione non funzia con il contentuto di $this->strut?

$this->strut è solo un metodo di quell'oggetto? mi sembra inappropriato per il suo scopo... direi più che è una variabile... non mi semra un metodo.

ARGGGGGGGHHHHHHHHHH odio restare fermo per giorni per un solo problema...

risposto 10 anni fa
arjuna
X 0 X

array push serve ad aggiungere un nuovo elemento all'array generale

questo è il motivo per cui non posso fare diversamente

qualsiasi soluzione temporanea non ha senso una volta che $struct deve tornare disponibile fuori della funzione che lo ha invocato e alimentato...

Da quello che ho capito dallo script che hai postato, quello che viene utilizzato in tutta la classe, ossia la variabile globale è quella che richiami facendo $this->struct...

Quella invece che utilizzi singolarmente nella funzione:

$struct, ha validità solo all'interno della funzione stessa.

Perciò, quello che ti avevo proposto sopra, non anadva a modifiacre la tua variabile globale, ma solo quella della funzione.

Dato che facendo

$struct = $this->struct;

abbiamo visto che non "faceva diventare $struct un array", ti avevo proposto di 'aggirare' il problema facendo il foreach di prima che restituiva sicuramente un array, te lo ripropongo:

$struct = array();
foreach($this->struct as $key=>$value)
 $struct[$key] = $value; //Copio l'array $this->struct nell'array $struct

//e poi puoi tranquillamente fare l'array_push
array_push($struct,$tag);

Ho capito che hai abbandonato l'idea di modificarlo come ti ho postato, vai tra ;) , ho voluto solo spiegarti che non era mia intenzione stravolgerti lo script...

Ciao & in bocca al lupo!

Lore

risposto 10 anni fa
Lore
Lore
1
X 0 X

Sono io che ho adottato la formula:

<?php

$struct = $this->struct;

array_push($struct, $tag);

?>

invece che :

<?php

array_push($this->struct, $tag);

?>

Lo script esige solo che ci sia un array da riempire e che questo sia globalmente disponibile dopo che la funzione che lo chiamo lo ha manipolato.

Ma se non mi legge l'array qualsiasi cosa non ha senso.

risposto 10 anni fa
arjuna
X 0 X

Potresti postare TUTTO il codice necessario a far girare lo script, così che possa provarlo sul mio PC?

 :bye:

risposto 10 anni fa
Gianni Tomasicchio
X 0 X

Innanzitutto ti posto un esempio di file xml:

sposa.xml

<?xml version='1.0'?>
<elenco>
   <foto nome='sposa08' link='album/sposa/sposa08.jpg' />
   <foto nome='sposa09' link='album/sposa/sposa09.jpg' />
   <foto nome='sposa10' link='album/sposa/sposa10.jpg' />
   <foto nome='sposa01' link='album/sposa/sposa01.jpg' />
   <foto nome='sposa02' link='album/sposa/sposa02.jpg' />
   <foto nome='sposa03' link='album/sposa/sposa03.jpg' />
   <foto nome='sposa04' link='album/sposa/sposa04.jpg' />
   <foto nome='sposa05' link='album/sposa/sposa05.jpg' />
   <foto nome='sposa06' link='album/sposa/sposa06.jpg' />
   <foto nome='sposa07' link='album/sposa/sposa07.jpg' />
</elenco>

Ecco lo script che lo richiama:

index.php

<?php

include ("galleryClass.php");

$gallery = new gallery ("sposa.xml");

$dati = $gallery->data;

echo "<pre>";
print_r($dati);
echo "</pre>";
die ();

?>

ecco il file incluso:

galleryClass.php

<?php

include ("parserXMLClass.php");

class gallery extends parserXML {

   // variabili Globali

    var $fdata;

   // costruttore
   function gallery ($fdata) {

      $this->data = $this->parse_file($fdata);

   }

} // end class

?>

e in fine il parser vero e proprio:

parserXMLClass.php

<?php

class parserXML {

   // variabili Globali

   var $struct;

   // costruttore
   function parserXML () {

      $this->struct = array ();

   }

   // Funzioni di callback

   function startElement($parser, $name, $attrs) {

      $tag = array("name"=>$name,"attrs"=>$attrs);

      array_push($this->struct, $tag);

   }

   function data($parser, $data) {

      if(trim($data)) {

         $this->struct[count($this->struct)-1]['data']=$data;

      }

   }

   function endElement($parser, $name) {

      $this->struct[count($this->struct)-2]['child'][] = $this->struct[count($this->struct)-1];

      array_pop($this->struct);

   }

   // Funzione che parsa il file passatogli nell'argomento e restituisce
   // una struttura ad albero oggetti-array contenente il documento

   function parse_file($file) {

      $xml_parser = xml_parser_create();

      xml_set_element_handler($xml_parser, array($this,"startElement"), array($this,"endElement"));

      xml_set_character_data_handler($xml_parser, array($this,"data"));

      $parse = xml_parse($xml_parser, file_get_contents($file));



      if(!$parse) {

         die("XML parsing error");

         xml_parser_free($xml_parser);

      }

      return $this->struct;

   }

}

?>

Questo è tutto.

Enjoy

risposto 10 anni fa
arjuna
X 0 X

Quando si usa l'ereditarietà delle classi bisogna ricordarsi che PHP eseguirà automaticamente SOLO il costruttore della classe più specializzata che ne possiede uno. Ad esempio se C eredita da B e B eredita da A, se esistono i costruttori di B e A ma non di C allora quando viene istanziato un oggetto C verra eseguito solo il costruttore di B (più specializzato rispetto a quello di A). Se C avesse avuto un costruttore (più specializzato di quello di B) allora solo questo sarebbe stato eseguito.

Se si vogliono eseguire i costruttori delle altre sottoclassi è quindi necessario richiamarli espicitamente nel costruttore richiamato automaticamente da PHP.

Devi quindi modificare il costruttore della classe gallery in modo che a sua volta esegua il costruttore della classe parserXML:

function gallery ($fdata) {

      parent::parserXML();

      $this->data = $this->parse_file($fdata);

   }

 :bye:

risposto 10 anni fa
Gianni Tomasicchio
X 0 X
Effettua l'accesso o registrati per rispondere a questa domanda