source: trunk/workflow/inc/class.utils.xml.php @ 7655

Revision 7655, 10.5 KB checked in by douglasz, 11 years ago (diff)

Ticket #3236 - Melhorias de performance no codigo do Expresso.

  • Property svn:executable set to *
Line 
1<?php
2require_once('class.utils.php');
3
4/**
5 * Generates XML from vectors and vice-versa
6 * @author Carlos Eduardo Nogueira Gonçalves
7 * @author Enderlin Ivan <enderlin.ivan@firegates.com> Classe Clean XML To Array
8 * @link http://www.phpclasses.org/browse/package/3598.html Classe Clean XML To Array
9 * @author Johnny Brochard <johnny.brochard@libertysurf.fr> Classe Array 2 XML
10 * @link http://www.phpclasses.org/browse/package/1826.html Classe Array 2 XML
11 * @version 1.0
12 * @license http://www.gnu.org/copyleft/gpl.html GPL
13 * @package Workflow
14 */
15class XmlUtils extends Utils
16{
17        /**
18         * Xml parser container
19         * @var resource parser
20         * @access private
21         * @see XmlUtils::fromXML
22         */
23        var $parser;
24        /**
25         * Parse result
26         * @var array pOut
27         * @access private
28         * @see XmlUtils::fromXML
29         */
30        var $pOut = array();
31        /**
32         * Contains the overlap tag temporarily
33         * @var array track
34         * @access private
35         * @see XmlUtils::fromXML
36         */
37        var $track = array();
38        /**
39         * Current tag level
40         * @var string tmpLevel
41         * @access private
42         * @see XmlUtils::fromXML
43         */
44        var $tmpLevel;
45        /**
46         * Attribut of current tag
47         * @var array tmpAttrLevel
48         * @access private
49         * @see XmlUtils::fromXML
50         */
51        var $tmpAttrLevel = array();
52        /**
53         * Write result
54         * @var string wOut
55         * @access private
56         * @see XmlUtils::fromXML
57         */
58        var $wOut = '';
59
60        /**
61         * XML Array
62         * @var array
63         * @access private
64         * @see XmlUtils::toXML
65         */
66        var $XMLArray;
67
68        /**
69         * DOM document instance
70         * @var DomDocument
71         * @access private
72         * @see XmlUtils::toXML
73         */
74        var $doc;
75
76        /**
77         * Gets vector from XML
78         *
79         * @access  public
80         * @param   string $src Source
81         * @param   string $typeof Source type : NULL, FILE, CURL
82         * @param   string $encoding Encoding type
83         * @return  array
84         */
85        function fromXML ( $src, $typeof = 'FILE', $encoding = 'UTF-8' )
86        {
87                // ini;
88                // (re)set array;
89                $this->pOut = array();
90                $this->parser = xml_parser_create();
91                xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
92                xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $encoding);
93                xml_set_object($this->parser, $this);
94                xml_set_element_handler($this->parser, '_startHandler', '_endHandler');
95                xml_set_character_data_handler($this->parser, '_contentHandler');
96                // format source;
97                if($typeof == NULL) {
98                        $data = $src;
99                }
100                elseif($typeof == 'FILE') {
101                        $fop = fopen($src, 'r');
102                        $data = fread($fop, filesize($src));
103                        fclose($fop);
104                }
105                elseif($typeof == 'CURL') {
106                        $curl = curl_init();
107                        curl_setopt($curl, CURLOPT_URL, $src);
108                        curl_setopt($curl, CURLOPT_HEADER, 0);
109                        $data = curl_exec($curl);
110                        curl_close($curl);
111                }
112                else {
113                        $this->raiseError('O analisador XML precisa de informações', __FILE__, __LINE__);
114                }
115                // parse $data;
116                $parse = xml_parse($this->parser, $data);
117                if(!$parse) {
118                        $this->raiseError
119                        (
120                                'XML Error : '                                      .
121                                xml_error_string(xml_get_error_code($this->parser)) .
122                                ' at line '                                         .
123                                xml_get_current_line_number($this->parser)          ,
124                                __FILE__                                            ,
125                                __LINE__
126                        );
127                }
128                // destroy parser;
129                xml_parser_free($this->parser);
130                // unset extra vars;
131                unset($data,
132                          $this->track,
133                          $this->tmpLevel,
134                          $this->tmpAttrLevel);
135                // remove global tag and return the result;
136                return $this->pOut[0][key($this->pOut[0])];
137        }
138
139        /**
140         * Converts vectors to XML
141         *
142         * @param array $input Vector, associative or not, to be parsed into XML
143         * @param string $rootName Root tag's label
144         * @access public
145         * @return string
146         */
147        function toXML($input, $rootName="")
148        {
149                if (is_array($input) && count($input) != 0){
150                        $this->XMLArray = $input;
151                } else {
152                        $this->raiseError('O argumento a ser convertido deve ser um array com pelo menos 1 elemento', __FILE__, __LINE__);
153                }
154                global $debug;
155                $this->doc = domxml_new_doc("1.0");
156                $arr = array();
157                if (count($this->XMLArray) > 1) {
158                        if ($rootName != "") {
159                                $root = $this->doc->create_element($rootName);
160                        } else {
161                                $root = $this->doc->create_element("root");
162                                $rootName = "root";
163                        }
164                        $arr = $this->XMLArray;
165                } else {
166                        $key = key($this->XMLArray);
167                        $val = $this->XMLArray[$key];
168                        if (!is_int($key)) {
169                                $root = $this->doc->create_element($key);
170                                $rootName = $key;
171                        } else {
172                                if ($rootName != "") {
173                                        $root = $this->doc->create_element($rootName);
174                                } else {
175                                        $root = $this->doc->create_element("root");
176                                        $rootName = "root";
177                                }
178                        }
179                        $arr = $this->XMLArray[$key];
180                }
181                $root = $this->doc->append_child($root);
182                $this->_addArray($arr, $root, $rootName);
183                return($this->doc->dump_mem(true));
184        }
185
186        /**
187         * Manages the open tag, and these attributs by callback
188         * The purpose is to create a pointer : {{int ptr}}
189         * If the pointer exists, we have a multi-tag situation
190         * Tag name  is stocked like : '<tag>'
191         * Attributs is stocked like : '<tag>-ATTR'
192         * Returns TRUE but built $this->pOut
193         *
194         * @access  private
195         * @param   resource $parser Parser resource
196         * @param   string $tag Tag name
197         * @param   array $attr Attribut
198         * @return  bool
199         * @see XmlUtils::fromXML
200         */
201        function _startHandler ( $parser, $tag, $attr )
202        {
203                static $attrLevel = -1;
204                static $fnstAttr = TRUE;
205                ++$attrLevel;
206                // built $this->track;
207                $this->track[] = $tag;
208                // place pointer to the end;
209                end($this->track);
210                // temp level;
211                $this->tmpLevel = key($this->track);
212                // built $this->pOut;
213                if(!isset($this->pOut[key($this->track)][$tag])) {
214                        $this->pOut[key($this->track)][$tag] = '{{'.key($this->track).'}}';
215                        $attrLevel = 0;
216                        $this->tmpAttrLevel = array();
217                }
218                // built attributs;
219                if(!empty($attr)) {
220                        $this->tmpAttrLevel[] = $attrLevel;
221                        end($this->tmpAttrLevel);
222                        // it's the first attribut;
223                        if(!isset($this->pOut[key($this->track)][$tag.'-ATTR'])) {
224                                $this->pOut[key($this->track)][$tag.'-ATTR'] = $attr;
225                        } else { // or it's not the first;
226                                // so it's the second;
227                                if($fnstAttr === TRUE) {
228                                        $this->pOut[key($this->track)][$tag.'-ATTR'] = array(
229                                                prev($this->tmpAttrLevel) => $this->pOut[key($this->track)][$tag.'-ATTR'],
230                                                next($this->tmpAttrLevel) => $attr
231                                        );
232                                        $fnstAttr = FALSE;
233                                } else { // or one other;
234                                        $this->pOut[key($this->track)][$tag.'-ATTR'][current($this->tmpAttrLevel)] = $attr;
235                                }
236                        }
237                }
238                return TRUE;
239        }
240
241        /**
242         * Detects the pointer, or the multi-tag by callback
243         * If we have a pointer, the method replaces this pointer by the content
244         * Else we have a multi-tag, the method add a element to this array
245         * This method returns TRUE but built $this->pOut
246         *
247         * @access  private
248         * @param   resource $parser Parser resource
249         * @param   string $contentHandler Tag content
250         * @return  bool
251         * @see XmlUtils::fromXML
252         */
253        function _contentHandler ( $parser, $contentHandler )
254        {
255                // remove all spaces;
256                if(!preg_match('#^[[:space:]]*$#', $contentHandler)) {
257                        // $contentHandler is a string;
258                        if(is_string($this->pOut[key($this->track)][current($this->track)])) {
259                                // then $contentHandler is a pointer : {{int ptr}}     case 1;
260                                if(preg_match('#{{([0-9]+)}}#', $this->pOut[key($this->track)][current($this->track)])) {
261                                        $this->pOut[key($this->track)][current($this->track)] = $contentHandler;
262                                } else { // or then $contentHandler is a multi-tag content      case 2;
263                                        $this->pOut[key($this->track)][current($this->track)] = array(
264                                                0 => $this->pOut[key($this->track)][current($this->track)],
265                                                1 => $contentHandler
266                                        );
267                                }
268                        } else { // or $contentHandler is an array;
269                                // then $contentHandler is the multi-tag array         case 1;
270                                if(isset($this->pOut[key($this->track)][current($this->track)][0])) {
271                                        $this->pOut[key($this->track)][current($this->track)][] = $contentHandler;
272                                } else { // or then $contentHandler is a node-tag               case 2;
273                                        $this->pOut[key($this->track)][current($this->track)] = array(
274                                                0 => $this->pOut[key($this->track)][current($this->track)],
275                                                1 => $contentHandler
276                                        );
277                                }
278                        }
279                }
280                return TRUE;
281        }
282
283        /**
284         * Detects the last pointer by callback
285         * Move the last tags block up
286         * And reset some temp variables
287         * This method returns TRUE but built $this->pOut
288         * @param   resource $parser Parser resource
289         * @param   string $tag Tag name
290         * @return  bool
291         * @see XmlUtils::fromXML
292         * @access  public
293         */
294        function _endHandler ( $parser, $tag )
295        {
296                // if level--;
297                if(key($this->track) == $this->tmpLevel-1) {
298                        // search up tag;
299                        // use array_keys if an empty tag exists (taking the last tag);
300                        // if it's a normal framaset;
301                        $keyBack = array_keys($this->pOut[key($this->track)], '{{'.key($this->track).'}}');
302                        $count = count($keyBack);
303                        if($count != 0) {
304                                $keyBack = $keyBack{$count-1};
305                                // move this level up;
306                                $this->pOut[key($this->track)][$keyBack] = $this->pOut[key($this->track)+1];
307                        } else { // if we have a multi-tag framaset ($count == 0);
308                                // if place is set;
309                                if(isset($this->pOut[key($this->track)][current($this->track)][0])) {
310                                        // if it's a string, we built an array;
311                                        if(is_string($this->pOut[key($this->track)][current($this->track)])) {
312                                                $this->pOut[key($this->track)][current($this->track)] = array(
313                                                        0 => $this->pOut[key($this->track)][current($this->track)],
314                                                        1 => $this->pOut[key($this->track)+1]
315                                                );
316                                        } else { // else add an index into the array;
317                                                $this->pOut[key($this->track)][current($this->track)][] = $this->pOut[key($this->track)+1];
318                                        }
319                                } else { // else set the place;
320                                        $this->pOut[key($this->track)][current($this->track)] = array(
321                                                0 => $this->pOut[key($this->track)][current($this->track)],
322                                                1 => $this->pOut[key($this->track)+1]
323                                        );
324                                }
325                        }
326                        // kick $this->pOut level out;
327                        array_pop($this->pOut);
328                        end($this->pOut);
329                }
330                // re-temp level;
331                $this->tmpLevel = key($this->track);
332                // kick $this->track level out;
333                array_pop($this->track);
334                end($this->track);
335                return TRUE;
336        }
337
338        /**
339         * Recursively converts nested arrays to nested XML tags
340         *
341         * @param array $arr
342         * @param object &$n DomNode instance
343         * @param string $name
344         * @see XmlUtils::toXML
345         * @access public
346         * @return void
347         */
348        function _addArray($arr, &$n, $name="")
349        {
350                foreach ($arr as $key => $val) {
351                        if (is_int($key)) {
352                                if (strlen($name)>1) {
353                                        $newKey = substr($name, 0, strlen($name)-1);
354                                } else {
355                                        $newKey="item";
356                                }
357                        } else {
358                                $newKey = $key;
359                        }
360                        $node = $this->doc->create_element($newKey);
361                        if (is_array($val)) {
362                                $this->_addArray($arr[$key], $node, $key);
363                        } else {
364                                $nodeText = $this->doc->create_text_node($val);
365                                $node->append_child($nodeText);
366                        }
367                        $n->append_child($node);
368                }
369        }
370}
371?>
Note: See TracBrowser for help on using the repository browser.