Table des matières
Niveau
..........
En rapport...

Pourquoi

Vous me direz que des dizaine de parseur existe, par exemple, en bundle dans php5 on a simpleXML ou le DOM, dans php4 il y avais DomXml.
L'idée de faire mon propre parseur est d'ailleur venu de la : la différence de parseur entre chaque version de php !
Marre de devoir adapter le code a chaque mise a jour !
J'ai donc mis au point cette classe qui prend un contenu xml et le converti en tableau, et ceci, sans passer par aucun parseur. Seul le moteur d'expression réguliere PECL de php est utlisé.
Je ne garanti pas sa rapidité sur un gros XML mais pour la plus part des cas, cela ira nikel (j'ai tester avec de gros flux RSS sans probleme).
!!La version actuelle est un 1er Jet, donc certain bug son a prévoir même si je l'ai pas mal testé.!!

Code

php
 
<?php
class xmlToarray {
	/* constructeur */
	function xmlToarray($xml, $trace=false) {
		//des/active le debug
		$this->trace=$trace;
		//Cherche l'entête
		/*<?xml version="1.0" encoding="ISO-8859-1" ?>*/
		if (preg_match("/<[^>]*xml[^>]*encoding[^>]*>/", $xml,$matches)) {
			$xml=preg_replace('/[\n\r\t]/','',$xml);
			$this->xml[0]=substr($xml,strlen($matches[0]),strlen($xml)-strlen($matches[0]));
			//$this->_Showtrace('xml valide');
			//Stoke l'encoding
			$this->arr='';
			preg_match('/encoding="([^"]*)"/', $matches[0],$matches['encoding']);
			$this->arr['_encoding']=$matches['encoding'][1];
			preg_match('/version="([^"]*)"/', $matches[0],$matches['version']);
			$this->arr['_version']=$matches['version'][1];
			//$this->_Showtrace('version :'.$matches['version'][1]);
			//$this->_Showtrace('encoding:'.$matches['encoding'][1]);
			return true;
		}
		//$this->_Showtrace('xml invalide');
		return false;
	}
 
	/* Converti le xml en array*/
	function getContent() {
		$patternBalise="/<([^>]*)>/";
		$patternBaliseName="/([^ \/>]*)/";
		$patternBaliseAttrib='/ ([^=]*)="([^"]*)"/';
		$patternBaliseFermeture="/<\/%s>/";
		$Noeuds='$this->arr';
		$Niveau=0;
		$nivMatch='';
		$nivMatchold[0]='';
		//Root == xml[0]
		while ($Niveau>=0) {
			preg_match($patternBalise, $this->xml[$Niveau],$matches);
			if (@$matches[1]!='') {
				$matches[1]=trim($matches[1]);
			} else {
				$Niveau--;
				continue;
			}
 
			//recupere le nom de lelement
			preg_match($patternBaliseName, $matches[1],$matches['name']);
			$matches['name'][1]=trim($matches['name'][1]);
 
			//Increment des niveau de complexe
			$Nencours='';
			for ($j=0;$j<=$Niveau-1;$j++)
				$Nencours.=$NodeNiveau[$j];
			$Nencours.=$matches['name'][1];
 
			if (@$nivMatchold[$Nencours]==$Nencours) {
				$nivMatch[$Nencours]++;
				//echo '---*'.$nivMatchold[$Nencours].'=='.$Nencours.'*---'.$nivMatch[$Nencours].'+<br />';
			} else {
				$nivMatch[$Nencours]=0;
				//echo '---*'.@$nivMatchold[$Nencours].'=='.$Nencours.'*---'.$nivMatch[$Nencours].'+<br />';
			}
			$nivMatchold[$Nencours]=$Nencours;
 
			$NodeNiveau[$Niveau]=$matches['name'][1];
			$Noeuds='$this->arr';
			for ($j=0;$j<=$Niveau-1;$j++)
				$Noeuds.='["'.$NodeNiveau[$j].'"]';
			$aNoeuds=$Noeuds;
			$aNoeuds.='["'.$NodeNiveau[$Niveau].'"]';
			$aNoeuds.='["'.$nivMatch[$Nencours].'"]';
			$Noeuds.='["'.$nivMatch[$Nencours].'"]';
			$Noeuds.='["'.$NodeNiveau[$Niveau].'"]';
 
			//$this->_Showtrace('matches:'.$Noeuds);
			//les attribut
			preg_match_all($patternBaliseAttrib, $matches[1],$matches['attrib']);
			foreach($matches['attrib'][1] as $k => $v) {
				eval($aNoeuds.'["@'.trim($v).'"]=$matches[\'attrib\'][2][$k];');
				$this->_Showtrace('++'.$aNoeuds.'["@'.trim($v).'"]=$matches[\'attrib\'][2][$k];');
			}
			//Chope le contenu de la balise en cours si il sagit de xml
			$p=sprintf($patternBaliseFermeture,$matches['name'][1]);
			preg_match($p, $this->xml[$Niveau],$matches['fin'],PREG_OFFSET_CAPTURE);
			//cas d'une fermeture normale
			if (@$matches['fin'][0][0]!='') {
				//dans le niveau suivant on met le contenu de la balise				
				$this->xml[$Niveau+1]=substr($this->xml[$Niveau],strlen($matches[1])+2,$matches['fin'][0][1]-(strlen($matches[1])+2));
				$this->xml[$Niveau+1]=trim($this->xml[$Niveau+1]);
				//puis on efface du niveau en cours la balise		
 
				$this->xml[$Niveau]=preg_replace("/<".$matches['name'][1]."[^>]*>.*<\/".$matches['name'][1].">/U","",$this->xml[$Niveau],1);
 
				$this->xml[$Niveau]=trim($this->xml[$Niveau]);
				//et on change de niveau
				$Niveau++;
				if (strlen($this->xml[$Niveau])==0) {
					//balise vide
					$Niveau--;
				} else if (($this->xml[$Niveau]{0} != '<') || (($this->xml[$Niveau]{0}=='<') && ($this->xml[$Niveau]{1}=='!'))) {
					//Fin de niveau
					$this->xml[$Niveau]=str_replace('<![CDATA[','',$this->xml[$Niveau]);
					$this->xml[$Niveau]=str_replace(']]>','',$this->xml[$Niveau]);
					eval($Noeuds.'["#text"]=$this->xml[$Niveau];');
					$this->_Showtrace('--'.$Noeuds.'["#text"]=$this->xml[$Niveau];');
					$this->xml[$Niveau]='';
					$Niveau--;
				}
			} else {
				//si il n'y a pas de balise fermante normale, c'est kil n'y a pas de sous niveau
				//on enleve aussi cette balise
				$this->xml[$Niveau]=preg_replace("/<".$matches['name'][1]."[^>]*\/>/","",$this->xml[$Niveau],1);
				$this->xml[$Niveau]=trim($this->xml[$Niveau]);
				//$this->_Showtrace('..'.$this->xml[$Niveau]);
			}			
		}
		$this->_DelZero($this->arr);
		return ($this->arr);
	}
	function _DelZero(&$a) {
	/*
		foreach ($a['rss'][0] as $k => $v) {
			$a['rss'][$k]=$a['rss'][0][$k];
		}
		unset($a['rss'][0]);
		return $a;
	*/
		foreach ($a as $k => &$v) {
			if (is_array($v)) {
 
				if ((@$v[0]!='') && (@$v[1]=='')) {
					foreach ($v[0] as $kk => &$vv) {
						$v[$kk]=$vv;
					}
					unset($v[0]);
				}
				$this->_DelZero($v);
			}
		}
		//return $a;
	}
 
	/*Affiche les echo de debug si activé */
	function _Showtrace($d,$pre=false) {
		if ($pre==true)
			echo '<pre>';
		if ($this->trace==true) {
			if ($pre==true) {
				echo date('H:i:s').' - ';
				print_r ($d);
				echo '<br />';
			} else {
				echo date('H:i:s').' - '.$d.'<br />';
			}			
		}
		if ($pre==true)
			echo '</pre>';
	}
}
 
?>

Utlisation

Comme toutes les classes, on déclare une nouvelle instance de la classe puis on apelle la fonction getContent() qui va renvoyé un tabelau issue du XML. exemple :

php
//met en bufffer le contenu du fichier XML
$x = file_get_contents( 'a.xml' );
//instancie la classe en lui passant le contenu du fichier XML
$a=new xmlToarray($x);
//Apelle le parseur
$c=$a->getContent();
//Affiche $c, le tabelau renvoyé par le parseur.
echo '<hr /><pre>';
print_r($c);
echo '</pre>';

Notes

Pour que la classe concidere le XML valide celui-ci doit obligatoirement avoir une en-t^te qui spécifie l'encoding ! exemple :

xml
<?xml version="1.0" encoding="ISO-8859-1" ?>