source: branches/version-2_13-dev/data/module/XML/Unserializer.php @ 21713

Revision 21713, 29.3 KB checked in by AMUAMU, 12 years ago (diff)

#1604 (外部連携用APIの実装) 基本機構実装、Amazon API相当の機能の実装(商品一覧系)

Line 
1<?PHP
2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
4/**
5 * XML_Unserializer
6 *
7 * Parses any XML document into PHP data structures.
8 *
9 * PHP versions 4 and 5
10 *
11 * LICENSE:
12 *
13 * Copyright (c) 2003-2008 Stephan Schmidt <schst@php.net>
14 * All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 *
20 *    * Redistributions of source code must retain the above copyright
21 *      notice, this list of conditions and the following disclaimer.
22 *    * Redistributions in binary form must reproduce the above copyright
23 *      notice, this list of conditions and the following disclaimer in the
24 *      documentation and/or other materials provided with the distribution.
25 *    * The name of the author may not be used to endorse or promote products
26 *      derived from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
29 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
30 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
32 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
36 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * @category  XML
41 * @package   XML_Serializer
42 * @author    Stephan Schmidt <schst@php.net>
43 * @copyright 2003-2008 Stephan Schmidt <schst@php.net>
44 * @license   http://opensource.org/licenses/bsd-license New BSD License
45 * @version   CVS: $Id: Unserializer.php 303099 2010-09-06 16:23:06Z clockwerx $
46 * @link      http://pear.php.net/package/XML_Serializer
47 * @see       XML_Unserializer
48 */
49
50/**
51 * uses PEAR error managemt
52 */
53require_once 'PEAR.php';
54
55/**
56 * uses XML_Parser to unserialize document
57 */
58require_once 'XML/Parser.php';
59
60/**
61 * option: Convert nested tags to array or object
62 *
63 * Possible values:
64 * - array
65 * - object
66 * - associative array to define this option per tag name
67 */
68define('XML_UNSERIALIZER_OPTION_COMPLEXTYPE', 'complexType');
69
70/**
71 * option: Name of the attribute that stores the original key
72 *
73 * Possible values:
74 * - any string
75 */
76define('XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY', 'keyAttribute');
77
78/**
79 * option: Name of the attribute that stores the type
80 *
81 * Possible values:
82 * - any string
83 */
84define('XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE', 'typeAttribute');
85
86/**
87 * option: Name of the attribute that stores the class name
88 *
89 * Possible values:
90 * - any string
91 */
92define('XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS', 'classAttribute');
93
94/**
95 * option: Whether to use the tag name as a class name
96 *
97 * Possible values:
98 * - true or false
99 */
100define('XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME', 'tagAsClass');
101
102/**
103 * option: Name of the default class
104 *
105 * Possible values:
106 * - any string
107 */
108define('XML_UNSERIALIZER_OPTION_DEFAULT_CLASS', 'defaultClass');
109
110/**
111 * option: Whether to parse attributes
112 *
113 * Possible values:
114 * - true or false
115 */
116define('XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE', 'parseAttributes');
117
118/**
119 * option: Key of the array to store attributes (if any)
120 *
121 * Possible values:
122 * - any string
123 * - false (disabled)
124 */
125define('XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY', 'attributesArray');
126
127/**
128 * option: string to prepend attribute name (if any)
129 *
130 * Possible values:
131 * - any string
132 * - false (disabled)
133 */
134define('XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND', 'prependAttributes');
135
136/**
137 * option: key to store the content,
138 * if XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE is used
139 *
140 * Possible values:
141 * - any string
142 */
143define('XML_UNSERIALIZER_OPTION_CONTENT_KEY', 'contentName');
144
145/**
146 * option: map tag names
147 *
148 * Possible values:
149 * - associative array
150 */
151define('XML_UNSERIALIZER_OPTION_TAG_MAP', 'tagMap');
152
153/**
154 * option: list of tags that will always be enumerated
155 *
156 * Possible values:
157 * - indexed array
158 */
159define('XML_UNSERIALIZER_OPTION_FORCE_ENUM', 'forceEnum');
160
161/**
162 * option: Encoding of the XML document
163 *
164 * Possible values:
165 * - UTF-8
166 * - ISO-8859-1
167 */
168define('XML_UNSERIALIZER_OPTION_ENCODING_SOURCE', 'encoding');
169
170/**
171 * option: Desired target encoding of the data
172 *
173 * Possible values:
174 * - UTF-8
175 * - ISO-8859-1
176 */
177define('XML_UNSERIALIZER_OPTION_ENCODING_TARGET', 'targetEncoding');
178
179/**
180 * option: Callback that will be applied to textual data
181 *
182 * Possible values:
183 * - any valid PHP callback
184 */
185define('XML_UNSERIALIZER_OPTION_DECODE_FUNC', 'decodeFunction');
186
187/**
188 * option: whether to return the result of the unserialization from unserialize()
189 *
190 * Possible values:
191 * - true
192 * - false (default)
193 */
194define('XML_UNSERIALIZER_OPTION_RETURN_RESULT', 'returnResult');
195
196/**
197 * option: set the whitespace behaviour
198 *
199 * Possible values:
200 * - XML_UNSERIALIZER_WHITESPACE_KEEP
201 * - XML_UNSERIALIZER_WHITESPACE_TRIM
202 * - XML_UNSERIALIZER_WHITESPACE_NORMALIZE
203 */
204define('XML_UNSERIALIZER_OPTION_WHITESPACE', 'whitespace');
205
206/**
207 * Keep all whitespace
208 */
209define('XML_UNSERIALIZER_WHITESPACE_KEEP', 'keep');
210
211/**
212 * remove whitespace from start and end of the data
213 */
214define('XML_UNSERIALIZER_WHITESPACE_TRIM', 'trim');
215
216/**
217 * normalize whitespace
218 */
219define('XML_UNSERIALIZER_WHITESPACE_NORMALIZE', 'normalize');
220
221/**
222 * option: whether to ovverride all options that have been set before
223 *
224 * Possible values:
225 * - true
226 * - false (default)
227 */
228define('XML_UNSERIALIZER_OPTION_OVERRIDE_OPTIONS', 'overrideOptions');
229
230/**
231 * option: list of tags, that will not be used as keys
232 */
233define('XML_UNSERIALIZER_OPTION_IGNORE_KEYS', 'ignoreKeys');
234
235/**
236 * option: whether to use type guessing for scalar values
237 */
238define('XML_UNSERIALIZER_OPTION_GUESS_TYPES', 'guessTypes');
239
240/**
241 * error code for no serialization done
242 */
243define('XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION', 151);
244
245/**
246 * XML_Unserializer
247 *
248 * class to unserialize XML documents that have been created with
249 * XML_Serializer. To unserialize an XML document you have to add
250 * type hints to the XML_Serializer options.
251 *
252 * If no type hints are available, XML_Unserializer will guess how
253 * the tags should be treated, that means complex structures will be
254 * arrays and tags with only CData in them will be strings.
255 *
256 * <code>
257 * require_once 'XML/Unserializer.php';
258 *
259 * //  be careful to always use the ampersand in front of the new operator
260 * $unserializer = &new XML_Unserializer();
261 *
262 * $unserializer->unserialize($xml);
263 *
264 * $data = $unserializer->getUnserializedData();
265 * </code>
266 *
267 * @category  XML
268 * @package   XML_Serializer
269 * @author    Stephan Schmidt <schst@php.net>
270 * @copyright 2003-2008 Stephan Schmidt <schst@php.net>
271 * @license   http://opensource.org/licenses/bsd-license New BSD License
272 * @version   Release: @package_version@
273 * @link      http://pear.php.net/package/XML_Serializer
274 * @see       XML_Serializer
275 */
276class XML_Unserializer extends PEAR
277{
278    /**
279     * list of all available options
280     *
281     * @access private
282     * @var    array
283     */
284    var $_knownOptions = array(
285                                XML_UNSERIALIZER_OPTION_COMPLEXTYPE,
286                                XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY,
287                                XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE,
288                                XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS,
289                                XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME,
290                                XML_UNSERIALIZER_OPTION_DEFAULT_CLASS,
291                                XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE,
292                                XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY,
293                                XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND,
294                                XML_UNSERIALIZER_OPTION_CONTENT_KEY,
295                                XML_UNSERIALIZER_OPTION_TAG_MAP,
296                                XML_UNSERIALIZER_OPTION_FORCE_ENUM,
297                                XML_UNSERIALIZER_OPTION_ENCODING_SOURCE,
298                                XML_UNSERIALIZER_OPTION_ENCODING_TARGET,
299                                XML_UNSERIALIZER_OPTION_DECODE_FUNC,
300                                XML_UNSERIALIZER_OPTION_RETURN_RESULT,
301                                XML_UNSERIALIZER_OPTION_WHITESPACE,
302                                XML_UNSERIALIZER_OPTION_IGNORE_KEYS,
303                                XML_UNSERIALIZER_OPTION_GUESS_TYPES
304                              );
305    /**
306     * default options for the serialization
307     *
308     * @access private
309     * @var    array
310     */
311    var $_defaultOptions = array(
312        // complex types will be converted to arrays, if no type hint is given
313        XML_UNSERIALIZER_OPTION_COMPLEXTYPE => 'array',
314
315        // get array key/property name from this attribute
316        XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY => '_originalKey',
317
318        // get type from this attribute
319        XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE => '_type',
320
321        // get class from this attribute (if not given, use tag name)
322        XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS => '_class',
323
324        // use the tagname as the classname
325        XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME => true,
326
327        // name of the class that is used to create objects
328        XML_UNSERIALIZER_OPTION_DEFAULT_CLASS => 'stdClass',
329
330        // parse the attributes of the tag into an array
331        XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE => false,
332
333        // parse them into sperate array (specify name of array here)
334        XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY => false,
335
336        // prepend attribute names with this string
337        XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND => '',
338
339        // put cdata found in a tag that has been converted
340        // to a complex type in this key
341        XML_UNSERIALIZER_OPTION_CONTENT_KEY => '_content',
342
343        // use this to map tagnames
344        XML_UNSERIALIZER_OPTION_TAG_MAP => array(),
345
346        // these tags will always be an indexed array
347        XML_UNSERIALIZER_OPTION_FORCE_ENUM => array(),
348
349        // specify the encoding character of the document to parse
350        XML_UNSERIALIZER_OPTION_ENCODING_SOURCE => null,
351
352        // specify the target encoding
353        XML_UNSERIALIZER_OPTION_ENCODING_TARGET => null,
354
355        // function used to decode data
356        XML_UNSERIALIZER_OPTION_DECODE_FUNC => null,
357
358        // unserialize() returns the result of the unserialization instead of true
359        XML_UNSERIALIZER_OPTION_RETURN_RESULT => false,
360
361        // remove whitespace around data
362        XML_UNSERIALIZER_OPTION_WHITESPACE => XML_UNSERIALIZER_WHITESPACE_TRIM,
363
364        // List of tags that will automatically be added to the parent,
365        // instead of adding a new key
366        XML_UNSERIALIZER_OPTION_IGNORE_KEYS => array(),
367
368        // Whether to use type guessing
369        XML_UNSERIALIZER_OPTION_GUESS_TYPES => false
370    );
371
372    /**
373     * current options for the serialization
374     *
375     * @access public
376     * @var    array
377     */
378    var $options = array();
379
380    /**
381     * unserialized data
382     *
383     * @access private
384     * @var    string
385     */
386    var $_unserializedData = null;
387
388    /**
389     * name of the root tag
390     *
391     * @access private
392     * @var    string
393     */
394    var $_root = null;
395
396    /**
397     * stack for all data that is found
398     *
399     * @access private
400     * @var    array
401     */
402    var $_dataStack = array();
403
404    /**
405     * stack for all values that are generated
406     *
407     * @access private
408     * @var    array
409     */
410    var $_valStack = array();
411
412    /**
413     * current tag depth
414     *
415     * @access private
416     * @var    int
417     */
418    var $_depth = 0;
419
420    /**
421     * XML_Parser instance
422     *
423     * @access   private
424     * @var      object XML_Parser
425     */
426    var $_parser = null;
427
428    /**
429     * constructor
430     *
431     * @param mixed $options array containing options for the unserialization
432     *
433     * @access public
434     */
435    function XML_Unserializer($options = null)
436    {
437        if (is_array($options)) {
438            $this->options = array_merge($this->_defaultOptions, $options);
439        } else {
440            $this->options = $this->_defaultOptions;
441        }
442    }
443
444    /**
445     * return API version
446     *
447     * @access   public
448     * @return string  $version API version
449     * @static
450     */
451    function apiVersion()
452    {
453        return '@package_version@';
454    }
455
456    /**
457     * reset all options to default options
458     *
459     * @return void
460     * @access public
461     * @see setOption(), XML_Unserializer(), setOptions()
462     */
463    function resetOptions()
464    {
465        $this->options = $this->_defaultOptions;
466    }
467
468    /**
469     * set an option
470     *
471     * You can use this method if you do not want
472     * to set all options in the constructor
473     *
474     * @param string $name  name of option
475     * @param mixed  $value value of option
476     *
477     * @return void
478     * @access public
479     * @see resetOption(), XML_Unserializer(), setOptions()
480     */
481    function setOption($name, $value)
482    {
483        $this->options[$name] = $value;
484    }
485
486    /**
487     * sets several options at once
488     *
489     * You can use this method if you do not want
490     * to set all options in the constructor
491     *
492     * @param array $options options array
493     *
494     * @return void
495     * @access public
496     * @see resetOption(), XML_Unserializer(), setOption()
497     */
498    function setOptions($options)
499    {
500        $this->options = array_merge($this->options, $options);
501    }
502
503    /**
504     * unserialize data
505     *
506     * @param mixed   $data    data to unserialize (string, filename or resource)
507     * @param boolean $isFile  data should be treated as a file
508     * @param array   $options options that will override
509     *                         the global options for this call
510     *
511     * @return boolean $success
512     * @access public
513     */
514    function unserialize($data, $isFile = false, $options = null)
515    {
516        $this->_unserializedData = null;
517        $this->_root             = null;
518
519        // if options have been specified, use them instead
520        // of the previously defined ones
521        if (is_array($options)) {
522            $optionsBak = $this->options;
523            if (isset($options[XML_UNSERIALIZER_OPTION_OVERRIDE_OPTIONS])
524                && $options[XML_UNSERIALIZER_OPTION_OVERRIDE_OPTIONS] == true
525            ) {
526                $this->options = array_merge($this->_defaultOptions, $options);
527            } else {
528                $this->options = array_merge($this->options, $options);
529            }
530        } else {
531            $optionsBak = null;
532        }
533
534        $this->_valStack  = array();
535        $this->_dataStack = array();
536        $this->_depth     = 0;
537
538        $this->_createParser();
539
540        if (is_string($data)) {
541            if ($isFile) {
542                $result = $this->_parser->setInputFile($data);
543                if (PEAR::isError($result)) {
544                    return $result;
545                }
546                $result = $this->_parser->parse();
547            } else {
548                $result = $this->_parser->parseString($data, true);
549            }
550        } else {
551            $this->_parser->setInput($data);
552            $result = $this->_parser->parse();
553        }
554
555        if ($this->options[XML_UNSERIALIZER_OPTION_RETURN_RESULT] === true) {
556            $return = $this->_unserializedData;
557        } else {
558            $return = true;
559        }
560
561        if ($optionsBak !== null) {
562            $this->options = $optionsBak;
563        }
564
565        if (PEAR::isError($result)) {
566            return $result;
567        }
568
569        return $return;
570    }
571
572    /**
573     * get the result of the serialization
574     *
575     * @access public
576     * @return string  $serializedData
577     */
578    function getUnserializedData()
579    {
580        if ($this->_root === null) {
581            return $this->raiseError('No unserialized data available. '
582                . 'Use XML_Unserializer::unserialize() first.',
583                XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION);
584        }
585        return $this->_unserializedData;
586    }
587
588    /**
589     * get the name of the root tag
590     *
591     * @access public
592     * @return string  $rootName
593     */
594    function getRootName()
595    {
596        if ($this->_root === null) {
597            return $this->raiseError('No unserialized data available. '
598                . 'Use XML_Unserializer::unserialize() first.',
599                XML_UNSERIALIZER_ERROR_NO_UNSERIALIZATION);
600        }
601        return $this->_root;
602    }
603
604    /**
605     * Start element handler for XML parser
606     *
607     * @param object $parser  XML parser object
608     * @param string $element XML element
609     * @param array  $attribs attributes of XML tag
610     *
611     * @return void
612     * @access private
613     */
614    function startHandler($parser, $element, $attribs)
615    {
616        if (isset($attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE]])
617        ) {
618            $type = $attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_TYPE]];
619
620            $guessType = false;
621        } else {
622            $type = 'string';
623            if ($this->options[XML_UNSERIALIZER_OPTION_GUESS_TYPES] === true) {
624                $guessType = true;
625            } else {
626                $guessType = false;
627            }
628        }
629
630        if ($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC] !== null) {
631            $attribs = array_map($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC],
632                $attribs);
633        }
634
635        $this->_depth++;
636        $this->_dataStack[$this->_depth] = null;
637
638        if (is_array($this->options[XML_UNSERIALIZER_OPTION_TAG_MAP])
639            && isset($this->options[XML_UNSERIALIZER_OPTION_TAG_MAP][$element])
640        ) {
641            $element = $this->options[XML_UNSERIALIZER_OPTION_TAG_MAP][$element];
642        }
643
644        $val = array(
645                     'name'         => $element,
646                     'value'        => null,
647                     'type'         => $type,
648                     'guessType'    => $guessType,
649                     'childrenKeys' => array(),
650                     'aggregKeys'   => array()
651                    );
652
653        if ($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_PARSE] == true
654            && (count($attribs) > 0)
655        ) {
656            $val['children'] = array();
657            $val['type']     = $this->_getComplexType($element);
658            $val['class']    = $element;
659
660            if ($this->options[XML_UNSERIALIZER_OPTION_GUESS_TYPES] === true) {
661                $attribs = $this->_guessAndSetTypes($attribs);
662            }
663            if ($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY] != false
664            ) {
665                $val['children'][$this->
666                    options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_ARRAYKEY]] = $attribs;
667            } else {
668                foreach ($attribs as $attrib => $value) {
669                    $val['children'][$this->
670                        options[XML_UNSERIALIZER_OPTION_ATTRIBUTES_PREPEND]
671                        . $attrib] = $value;
672                }
673            }
674        }
675
676        $keyAttr = false;
677
678        if (is_string($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY])) {
679            $keyAttr = $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY];
680        } elseif (is_array($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY])) {
681            if (isset($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]
682                [$element])
683            ) {
684                $keyAttr =
685                    $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY][$element];
686            } elseif (isset($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]
687                ['#default'])
688            ) {
689                $keyAttr = $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]
690                ['#default'];
691            } elseif (isset($this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]
692                ['__default'])
693            ) {
694                // keep this for BC
695                $keyAttr =
696                    $this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_KEY]
697                    ['__default'];
698            }
699        }
700
701        if ($keyAttr !== false && isset($attribs[$keyAttr])) {
702            $val['name'] = $attribs[$keyAttr];
703        }
704
705        if (isset($attribs[$this->
706            options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS]])
707        ) {
708            $val['class'] =
709                $attribs[$this->options[XML_UNSERIALIZER_OPTION_ATTRIBUTE_CLASS]];
710        }
711
712        array_push($this->_valStack, $val);
713    }
714
715    /**
716     * Try to guess the type of several values and
717     * set them accordingly
718     *
719     * @param array $array array containing the values
720     *
721     * @return array array, containing the values with their correct types
722     * @access private
723     */
724    function _guessAndSetTypes($array)
725    {
726        foreach ($array as $key => $value) {
727            $array[$key] = $this->_guessAndSetType($value);
728        }
729        return $array;
730    }
731
732    /**
733     * Try to guess the type of a value and
734     * set it accordingly
735     *
736     * @param string $value character data
737     *
738     * @return mixed value with the best matching type
739     * @access private
740     */
741    function _guessAndSetType($value)
742    {
743        if ($value === 'true') {
744            return true;
745        }
746        if ($value === 'false') {
747            return false;
748        }
749        if ($value === 'NULL') {
750            return null;
751        }
752        if (preg_match('/^[-+]?[0-9]{1,}\\z/', $value)) {
753            return intval($value);
754        }
755        if (preg_match('/^[-+]?[0-9]{1,}\.[0-9]{1,}\\z/', $value)) {
756            return doubleval($value);
757        }
758        return (string)$value;
759    }
760
761    /**
762     * End element handler for XML parser
763     *
764     * @param object $parser  XML parser object
765     * @param string $element element
766     *
767     * @return void
768     * @access private
769     */
770    function endHandler($parser, $element)
771    {
772        $value = array_pop($this->_valStack);
773        switch ($this->options[XML_UNSERIALIZER_OPTION_WHITESPACE]) {
774        case XML_UNSERIALIZER_WHITESPACE_KEEP:
775            $data = $this->_dataStack[$this->_depth];
776            break;
777        case XML_UNSERIALIZER_WHITESPACE_NORMALIZE:
778            $data = trim(preg_replace('/\s\s+/m', ' ',
779                $this->_dataStack[$this->_depth]));
780            break;
781        case XML_UNSERIALIZER_WHITESPACE_TRIM:
782        default:
783            $data = trim($this->_dataStack[$this->_depth]);
784            break;
785        }
786
787        // adjust type of the value
788        switch(strtolower($value['type'])) {
789
790        // unserialize an object
791        case 'object':
792            if (isset($value['class'])) {
793                $classname = $value['class'];
794            } else {
795                $classname = '';
796            }
797            // instantiate the class
798            if ($this->options[XML_UNSERIALIZER_OPTION_TAG_AS_CLASSNAME] === true
799                && class_exists($classname)
800            ) {
801                $value['value'] = new $classname;
802            } else {
803                $value['value'] =
804                    new $this->options[XML_UNSERIALIZER_OPTION_DEFAULT_CLASS];
805            }
806            if (trim($data) !== '') {
807                if ($value['guessType'] === true) {
808                    $data = $this->_guessAndSetType($data);
809                }
810                $value['children'][$this->
811                    options[XML_UNSERIALIZER_OPTION_CONTENT_KEY]] = $data;
812            }
813
814            // set properties
815            foreach ($value['children'] as $prop => $propVal) {
816                // check whether there is a special method to set this property
817                $setMethod = 'set'.$prop;
818                if (method_exists($value['value'], $setMethod)) {
819                    call_user_func(array(&$value['value'], $setMethod), $propVal);
820                } else {
821                    $value['value']->$prop = $propVal;
822                }
823            }
824            //  check for magic function
825            if (method_exists($value['value'], '__wakeup')) {
826                $value['value']->__wakeup();
827            }
828            break;
829
830        // unserialize an array
831        case 'array':
832            if (trim($data) !== '') {
833                if ($value['guessType'] === true) {
834                    $data = $this->_guessAndSetType($data);
835                }
836                $value['children'][$this->
837                    options[XML_UNSERIALIZER_OPTION_CONTENT_KEY]] = $data;
838            }
839            if (isset($value['children'])) {
840                $value['value'] = $value['children'];
841            } else {
842                $value['value'] = array();
843            }
844            break;
845
846        // unserialize a null value
847        case 'null':
848            $data = null;
849            break;
850
851        // unserialize a resource => this is not possible :-(
852        case 'resource':
853            $value['value'] = $data;
854            break;
855
856        // unserialize any scalar value
857        default:
858            if ($value['guessType'] === true) {
859                $data = $this->_guessAndSetType($data);
860            } else {
861                settype($data, $value['type']);
862            }
863
864            $value['value'] = $data;
865            break;
866        }
867        $parent = array_pop($this->_valStack);
868        if ($parent === null) {
869            $this->_unserializedData = &$value['value'];
870            $this->_root             = &$value['name'];
871            return true;
872        } else {
873            // parent has to be an array
874            if (!isset($parent['children']) || !is_array($parent['children'])) {
875                $parent['children'] = array();
876                if (!in_array($parent['type'], array('array', 'object'))) {
877                    $parent['type'] = $this->_getComplexType($parent['name']);
878                    if ($parent['type'] == 'object') {
879                        $parent['class'] = $parent['name'];
880                    }
881                }
882            }
883
884            if (in_array($element,
885                $this->options[XML_UNSERIALIZER_OPTION_IGNORE_KEYS])
886            ) {
887                $ignoreKey = true;
888            } else {
889                $ignoreKey = false;
890            }
891
892            if (!empty($value['name']) && $ignoreKey === false) {
893                // there already has been a tag with this name
894                if (in_array($value['name'], $parent['childrenKeys'])
895                    || in_array($value['name'],
896                    $this->options[XML_UNSERIALIZER_OPTION_FORCE_ENUM])
897                ) {
898                    // no aggregate has been created for this tag
899                    if (!in_array($value['name'], $parent['aggregKeys'])) {
900                        if (isset($parent['children'][$value['name']])) {
901                            $parent['children'][$value['name']] =
902                                array($parent['children'][$value['name']]);
903                        } else {
904                            $parent['children'][$value['name']] = array();
905                        }
906                        array_push($parent['aggregKeys'], $value['name']);
907                    }
908                    array_push($parent['children'][$value['name']], $value['value']);
909                } else {
910                    $parent['children'][$value['name']] = &$value['value'];
911                    array_push($parent['childrenKeys'], $value['name']);
912                }
913            } else {
914                array_push($parent['children'], $value['value']);
915            }
916            array_push($this->_valStack, $parent);
917        }
918
919        $this->_depth--;
920    }
921
922    /**
923     * Handler for character data
924     *
925     * @param object $parser XML parser object
926     * @param string $cdata  CDATA
927     *
928     * @return void
929     * @access private
930     */
931    function cdataHandler($parser, $cdata)
932    {
933        if ($this->options[XML_UNSERIALIZER_OPTION_DECODE_FUNC] !== null) {
934            $cdata = call_user_func($this->
935                options[XML_UNSERIALIZER_OPTION_DECODE_FUNC], $cdata);
936        }
937        $this->_dataStack[$this->_depth] .= $cdata;
938    }
939
940    /**
941     * get the complex type, that should be used for a specified tag
942     *
943     * @param string $tagname name of the tag
944     *
945     * @return string complex type ('array' or 'object')
946     * @access private
947     */
948    function _getComplexType($tagname)
949    {
950        if (is_string($this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE])) {
951            return $this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE];
952        }
953        if (isset($this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE][$tagname])) {
954            return $this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE][$tagname];
955        }
956        if (isset($this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE]['#default'])) {
957            return $this->options[XML_UNSERIALIZER_OPTION_COMPLEXTYPE]['#default'];
958        }
959        return 'array';
960    }
961
962    /**
963     * create the XML_Parser instance
964     *
965     * @return boolean
966     * @access private
967     */
968    function _createParser()
969    {
970        if (is_object($this->_parser)) {
971            $this->_parser->free();
972            unset($this->_parser);
973        }
974        $this->_parser = new XML_Parser($this->
975            options[XML_UNSERIALIZER_OPTION_ENCODING_SOURCE],
976            'event', $this->options[XML_UNSERIALIZER_OPTION_ENCODING_TARGET]);
977
978        $this->_parser->folding = false;
979        $this->_parser->setHandlerObj($this);
980        return true;
981    }
982}
983?>
Note: See TracBrowser for help on using the repository browser.