source: pmb4.1/trunk/fuentes/pmb/classes/xml_dom.class.php @ 478

Last change on this file since 478 was 478, checked in by mabarracus, 4 years ago

copy trusty code 4.1

  • Property svn:executable set to *
File size: 12.3 KB
Line 
1<?php
2// +-------------------------------------------------+
3// © 2002-2004 PMB Services / www.sigb.net pmb@sigb.net et contributeurs (voir www.sigb.net)
4// +-------------------------------------------------+
5// $Id: xml_dom.class.php,v 1.2 2012-10-26 06:51:43 dbellamy Exp $
6
7if (stristr($_SERVER['REQUEST_URI'], ".class.php")) die("no access");
8
9
10/**
11 * \mainpage Documentation du Client OAI
12 * \author PMB Services
13 * \author Florent TETART
14 * \date 2008
15 */
16
17//Un petit parser-dom élégant
18/**
19 * \brief Petit parser dom autonome et élégant
20 *
21 * Parse une chaine XML et permet un accès rapide par une interface simplifiée DOM.
22 * Cette classe fonctionne uassi bien en PHP4 que 5.
23 * \note Cette classe manipule des noeuds de type noeud (\ref noeud "voir l'attribut $tree").\n
24 * \note Des chemins sont utilisés pour accéder aux noeuds, les syntaxes sont détaillées dans les méthodes qui les utilisent :\n
25 * \note -\ref path_node "syntaxe des chemins pour la méthode get_node"\n
26 * \note -\ref path_nodes "syntaxe des chemins pour la méthode get_nodes"\n
27 *   
28 * @author Florent TETART
29 */
30class xml_dom {
31        var $xml;                               /*!< XML d'origine */
32        var $charset;                   /*!< Charset courant (iso-8859-1 ou utf-8) */
33        /**
34         * \brief Arbre des noeuds du document
35         *
36         * L'arbre est composé de noeuds qui ont la structure suivante :
37         * \anchor noeud
38         * \verbatim
39         $noeud = array(
40                NAME    => Nom de l'élément pour un noeud de type élément (TYPE = 1)
41                ATTRIBS => Tableau des attributs (nom => valeur)
42                TYPE    => 1 = Noeud élément, 2 = Noeud texte
43                CHILDS  => Tableau des noeuds enfants
44         )
45         \endverbatim
46         */
47        var $tree; 
48        var $error=false;               /*!< Signalement d'erreur : true : erreur lors du parse, false : pas d'erreur */
49        var $error_message="";  /*!< Message d'erreur correspondant à l'erreur de parse */
50        var $depth=0;                   /*!< \protected */
51        var $last_elt=array();  /*!< \protected */
52        var $n_elt=array();             /*!< \protected */
53        var $cur_elt=array();   /*!< \protected */
54        var $last_char=false;   /*!< \protected */
55       
56        /**
57         * \protected
58         */
59        function close_node() {
60                $this->last_elt[$this->depth-1]["CHILDS"][]=$this->cur_elt;
61                $this->last_char=false;
62                $this->cur_elt=$this->last_elt[$this->depth-1];
63                $this->depth--;
64        }
65       
66        /**
67         * \protected
68         */
69        function startElement($parser,$name,$attribs) {
70                if ($this->last_char) $this->close_node();
71                $this->last_elt[$this->depth]=$this->cur_elt;
72                $this->cur_elt=array('NAME'=>$name,'ATTRIBS'=>$attribs,'TYPE'=>1);
73                $this->last_char=false;
74                $this->depth++;
75        }
76       
77        /**
78         * \protected
79         */
80        function endElement($parser,$name) {
81                if ($this->last_char) $this->close_node();
82                $this->close_node();
83        }
84       
85        /**
86         * \protected
87         */
88        function charElement($parser,$char) {
89                if ($this->last_char) $this->close_node();
90                $this->last_char=true;
91                $this->last_elt[$this->depth]=$this->cur_elt;
92                $this->cur_elt=array('DATA'=>$char,'TYPE'=>2);
93                $this->depth++;
94        }
95       
96        /**
97         * \brief Instanciation du parser
98         *
99         * Le document xml est parsé selon le charset donné et une représentation sous forme d'arbre est générée
100         * @param string $xml XML a manipuler
101         * @param string $charset Charset du document XML
102         */
103        function xml_dom($xml,$charset="iso-8859-1") {
104                $this->charset=$charset;
105                $this->cur_elt=array("NAME"=>"document","TYPE"=>"0");
106               
107                //Initialisation du parser
108                $xml_parser=xml_parser_create($this->charset);
109                xml_set_object($xml_parser,$this);
110                xml_parser_set_option( $xml_parser, XML_OPTION_CASE_FOLDING, 0 );
111                xml_parser_set_option( $xml_parser, XML_OPTION_SKIP_WHITE, 1 );
112                xml_set_element_handler($xml_parser, "startElement", "endElement");
113                xml_set_character_data_handler($xml_parser,"charElement");
114               
115                if (!xml_parse($xml_parser, $xml)) {
116                $this->error_message=sprintf("XML error: %s at line %d",xml_error_string(xml_get_error_code($xml_parser)),xml_get_current_line_number($xml_parser));
117                $this->error=true;
118                }
119                $this->tree=$this->last_elt[0];
120        }
121       
122        /**
123         * \anchor path_node
124         * \brief Récupération d'un noeud par son chemin
125         *
126         * Recherche un noeud selon le chemin donné en paramètre. Un noeud de départ peut être précisé
127         * @param string $path Chemin du noeud recherché
128         * @param noeud [$node] Noeud de départ de la recherche (le noeud doit être de type 1)
129         * @return noeud Noeud correspondant au chemin ou \b false si non trouvé
130         * \note Les chemins ont la syntaxe suivante :
131         * \verbatim
132         <a>
133                <b>
134                        <c id="0">Texte</c>
135                        <c id="1">
136                                <d>Sous texte</d>
137                        </c>
138                        <c id="2">Texte 2</c>
139                </b>
140         </a>
141         
142         a/b/c          Le premier noeud élément c (<c id="0">Texte</c>)
143         a/b/c[2]/d     Le premier noeud élément d du deuxième noeud c (<d>Sous texte</d>)
144         a/b/c[3]       Le troisième noeud élément c (<c id="2">Texte 2</c>)
145         a/b/id@c       Le premier noeud élément c (<c id="0">Texte</c>). L'attribut est ignoré
146         a/b/id@c[3]    Le troisème noeud élément c (<c id="2">Texte 2</c>). L'attribut est ignoré
147         
148         Les attributs ne peuvent être cités que sur le noeud final.
149         \endverbatim
150         */
151        function get_node($path,$node="") {
152                if ($node=="") $node=&$this->tree;
153                $paths=explode("/",$path);
154                for ($i=0; $i<count($paths); $i++) {
155                        if ($i==count($paths)-1) {
156                                $pelt=explode("@",$paths[$i]);
157                                if (count($pelt)==1) { 
158                                        $p=$pelt[0]; 
159                                } else {
160                                        $p=$pelt[1];
161                                        $attr=$pelt[0];
162                                }
163                        } else $p=$paths[$i];
164                        if (preg_match("/\[([0-9]*)\]$/",$p,$matches)) {
165                                $name=substr($p,0,strlen($p)-strlen($matches[0]));
166                                $n=$matches[1];
167                        } else {
168                                $name=$p;
169                                $n=0;
170                        }
171                        $nc=0;
172                        $found=false;
173                        for ($j=0; $j<count($node["CHILDS"]); $j++) {
174                                if (($node["CHILDS"][$j]["TYPE"]==1)&&($node["CHILDS"][$j]["NAME"]==$name)) {
175                                        //C'est celui là !!
176                                        if ($nc==$n) {
177                                                $node=&$node["CHILDS"][$j];
178                                                $found=true;
179                                                break;
180                                        } else $nc++;
181                                }
182                        }
183                        if (!$found) return false;
184                }
185                return $node;
186        }
187       
188        /**
189         * \anchor path_nodes
190         * \brief Récupération d'un ensemble de noeuds par leur chemin
191         *
192         * Recherche d'un ensemble de noeuds selon le chemin donné en paramètre. Un noeud de départ peut être précisé
193         * @param string $path Chemin des noeuds recherchés
194         * @param noeud [$node] Noeud de départ de la recherche (le noeud doit être de type 1)
195         * @return array noeud Tableau des noeuds correspondants au chemin ou \b false si non trouvé
196         * \note Les chemins ont la syntaxe suivante :
197         * \verbatim
198         <a>
199                <b>
200                        <c id="0">Texte</c>
201                        <c id="1">
202                                <d>Sous texte</d>
203                        </c>
204                        <c id="2">Texte 2</c>
205                </b>
206         </a>
207         
208         a/b/c          Tous les éléments c fils de a/b
209         a/b/c[2]/d     Tous les éléments d fils de a/b et du deuxième élément c
210         a/b/id@c       Tous les noeuds éléments c fils de a/b. L'attribut est ignoré
211         \endverbatim
212         */
213        function get_nodes($path,$node="") {
214                $n=0;
215                $nodes="";
216                while ($nod=$this->get_node($path."[$n]",$node)) {
217                        $nodes[]=$nod;
218                        $n++;
219                }
220                return $nodes;
221        }
222       
223        /**
224         * \brief Récupération des données sérialisées d'un noeud élément
225         *
226         * Récupère sous forme texte les données d'un noeud élément :\n
227         * -Si c'est un élément qui n'a qu'un noeud texte comme fils, renvoie le texte\n
228         * -Si c'est un élément qui a d'autres éléments comme fils, la version sérialisée des enfants est renvoyée
229         * @param noeud $node Noeud duquel récupérer les données
230         * @param bool $force_entities true : les données sont renvoyées avec les entités xml, false : les données sont renvoyées sans entités
231         * @return string données sérialisées du noeud élément
232         */
233        function get_datas($node,$force_entities=false) {
234                $char="";
235                if ($node["TYPE"]!=1) return false;
236                //Recherche des fils et vérification qu'il n'y a que du texte !
237                $flag_text=true;
238                for ($i=0; $i<count($node["CHILDS"]); $i++) {
239                        if ($node["CHILDS"][$i]["TYPE"]!=2) $flag_text=false;
240                }
241                if ((!$flag_text)&&(!$force_entities)) {
242                        $force_entities=true;
243                }
244                for ($i=0; $i<count($node["CHILDS"]); $i++) {
245                        if ($node["CHILDS"][$i]["TYPE"]==2)
246                                if ($force_entities) 
247                                        $char.=htmlspecialchars($node["CHILDS"][$i]["DATA"],ENT_NOQUOTES,$this->charset);
248                                else $char.=$node["CHILDS"][$i]["DATA"];
249                        else {
250                                $char.="<".$node["CHILDS"][$i]["NAME"];
251                                if (count($node["CHILDS"][$i]["ATTRIBS"])) {
252                                        foreach ($node["CHILDS"][$i]["ATTRIBS"] as $key=>$val) {
253                                                $char.=" ".$key."=\"".htmlspecialchars($val,ENT_NOQUOTES,$this->charset)."\"";
254                                        }
255                                }
256                                $char.=">";
257                                $char.=$this->get_datas($node["CHILDS"][$i],$force_entities);
258                                $char.="</".$node["CHILDS"][$i]["NAME"].">";
259                        }
260                }
261                return $char;
262        }
263       
264        /**
265         * \brief Récupération des attributs d'un noeud
266         *
267         * Renvoie le tableau des attributs d'un noeud élément (Type 1)
268         * @param noeud $node Noeud élément duquel on veut les attributs
269         * @return mixed Tableau des attributs Nom => Valeur ou false si ce n'est pas un noeud de type 1
270         */
271        function get_attributes($node) {
272                if ($node["TYPE"]!=1) return false;
273                return $node["ATTRIBS"];
274        }
275       
276        function get_attribute($node, $name) {
277                if ($node["TYPE"]!=1) return false;
278                return $node["ATTRIBS"][$name];
279        }
280       
281        /**
282         * \brief Récupère les données ou l'attribut d'un noeud par son chemin
283         *
284         * Récupère les données sérialisées d'un noeud ou la valeur d'un attribut selon le chemin
285         * @param string $path chemin du noeud recherché
286         * @param noeud $node Noeud de départ de la recherche
287         * @return string Donnée sérialsiée ou valeur de l'attribut, \b false si le chemin n'existe pas
288         * \note Exemples de valeurs renvoyées selon le chemin :
289         * \verbatim
290         <a>
291                <b>
292                        <c id="0">Texte</c>
293                        <c id="1">
294                                <d>Sous texte</d>
295                        </c>
296                        <c id="2">Texte 2</c>
297                </b>
298         </a>
299         
300         a/b/c          Renvoie : "Texte"
301         a/b/c[2]/d     Renvoie : "Sous texte"
302         a/b/c[2]       Renvoie : "<d>Sous texte</d>"
303         a/b/c[3]       Renvoie : "Texte 2"
304         a/b/id@c       Renvoie : "0"
305         a/b/id@c[3]    Renvoie : "2"
306         \endverbatim
307         */
308        function get_value($path,$node="") {
309                $elt=$this->get_node($path,$node);
310                if ($elt) {
311                        $paths=explode("/",$path);
312                        $pelt=explode("@",$paths[count($paths)-1]);
313                        if (count($pelt)>1) {
314                                $a=$pelt[0];
315                                //Recherche de l'attribut
316                                if (preg_match("/\[([0-9]*)\]$/",$a,$matches)) {
317                                        $attr=substr($a,0,strlen($a)-strlen($matches[0]));
318                                        $n=$matches[1];
319                                } else {
320                                        $attr=$a;
321                                        $n=0;
322                                }
323                                $nc=0;
324                                $found=false;
325                                foreach($elt["ATTRIBS"] as $key=>$val) {
326                                        if ($key==$attr) {
327                                                //C'est celui là !!
328                                                if ($nc==$n) {
329                                                        $value=$val;
330                                                        $found=true;
331                                                        break;
332                                                } else $nc++;
333                                        }
334                                }
335                                if (!$found) $value="";
336                        } else {
337                                $value=$this->get_datas($elt);
338                        }
339                }
340                return $value;
341        }
342       
343        /**
344         * \brief Récupère les données ou l'attribut d'un ensemble de noeuds par leur chemin
345         *
346         * Récupère les données sérialisées ou la valeur d'un attribut d'un ensemble de noeuds selon le chemin
347         * @param string $path chemin des noeuds recherchés
348         * @param noeud $node Noeud de départ de la recherche
349         * @return array Tableau des données sérialisées ou des valeur de l'attribut, \b false si le chemin n'existe pas
350         * \note Exemples de valeurs renvoyées selon le chemin :
351         * \verbatim
352         <a>
353                <b>
354                        <c id="0">Texte</c>
355                        <c id="1">
356                                <d>Sous texte</d>
357                        </c>
358                        <c id="2">Texte 2</c>
359                </b>
360         </a>
361         
362         a/b/c          Renvoie : [0]=>"Texte",[1]=>"<d>Sous texte</d>",[2]=>"Texte 2"
363         a/b/c[2]/d     Renvoie : [0]=>"Sous texte"
364         a/b/id@c       Renvoie : [0]=>"0",[1]=>"1",[2]=>"2"
365         \endverbatim
366         */
367        function get_values($path,$node="") {
368                $n=0;
369                while ($elt=$this->get_node($path."[$n]",$node)) {
370                        $elts[$n]=$elt;
371                        $n++;
372                }
373                if (count($elts)) {
374                        for ($i=0; $i<count($elts); $i++) {
375                                $elt=$elts[$i];
376                                $paths=explode("/",$path);
377                                $pelt=explode("@",$paths[count($paths)-1]);
378                                if (count($pelt)>1) {
379                                        $a=$pelt[0];
380                                        //Recherche de l'attribut
381                                        if (preg_match("/\[([0-9]*)\]$/",$a,$matches)) {
382                                                $attr=substr($a,0,strlen($a)-strlen($matches[0]));
383                                                $n=$matches[1];
384                                        } else {
385                                                $attr=$a;
386                                                $n=0;
387                                        }
388                                        $nc=0;
389                                        $found=false;
390                                        foreach($elt["ATTRIBS"] as $key=>$val) {
391                                                if ($key==$attr) {
392                                                        //C'est celui là !!
393                                                        if ($nc==$n) {
394                                                                $values[]=$val;
395                                                                $found=true;
396                                                                break;
397                                                        } else $nc++;
398                                                }
399                                        }
400                                        if (!$found) $values[]="";
401                                } else {
402                                        $values[]=$this->get_datas($elt);
403                                }
404                        }
405                }
406                return $values;
407        }
408}
409
410?>
Note: See TracBrowser for help on using the repository browser.