root/trunk/src/main/php/net/stubbles/xml/serializer/stubXMLSerializer.php

Revision 1389, 7.7 kB (checked in by mikey, 3 months ago)

implemented enhancement #128: improved performance of XMLSerializer
Serializing a list of instances of the same object is much faster now.

Line 
1 <?php
2 /**
3  * XMLSerializer main class
4  *
5  * @author      Stephan Schmidt <schst@stubbles.net>
6  * @author      Frank Kleine <mikey@stubbles.net>
7  * @package     stubbles
8  * @subpackage  xml_serializer
9  */
10 stubClassLoader::load('net::stubbles::xml::stubXMLStreamWriter',
11                       'net::stubbles::xml::serializer::stubXMLSerializerObjectData'
12 );
13 /**
14  * XMLSerializer main class
15  *
16  * @package     stubbles
17  * @subpackage  xml_serializer
18  */
19 class stubXMLSerializer extends stubBaseObject
20 {
21     /**
22      * Option to define the root tag of the serialized document
23      */
24     const OPT_ROOT_TAG     = 'root-tag';
25     /**
26      * Option to define the strategy
27      */
28     const OPT_STRATEGY     = 'strategy';
29     /**
30      * Do not export any properties or methods
31      */
32     const STRATEGY_NONE    = 0;
33     /**
34      * export only public properties
35      */
36     const STRATEGY_PROPS   = 1;
37     /**
38      * export only public methods
39      */
40     const STRATEGY_METHODS = 2;
41     /**
42      * export public properties and methods
43      */
44     const STRATEGY_ALL     = 3;
45     /**
46      * Default options
47      *
48      * @var  array
49      */
50     private $defaultOpts = array(self::OPT_ROOT_TAG => null,
51                                  self::OPT_STRATEGY => self::STRATEGY_ALL
52                            );
53     /**
54      * Currently used options
55      *
56      * @var  array
57      */
58     private $opts;
59
60     /**
61      * serialize any data structure to XML
62      *
63      * @param  mixed                $data       data to serialize
64      * @param  stubXMLStreamWriter  $xmlWriter  XML Writer to use
65      * @param  array                $opts       Options to influence the serializing
66      */
67     public function serialize($data, stubXMLStreamWriter $xmlWriter, array $opts = array())
68     {
69         // set the currently used options
70         $this->opts = array_merge($this->defaultOpts, $opts);
71         $this->serializeDispatcher($data, $xmlWriter, ((isset($this->opts[self::OPT_ROOT_TAG]) == true) ? ($this->opts[self::OPT_ROOT_TAG]) : (null)));
72     }
73
74     /**
75      * serialize any data structure to XML
76      *
77      * @param  mixed                $data       data to serialize
78      * @param  stubXMLStreamWriter  $xmlWriter  XML Writer to use
79      * @param  string               $tagName    name of the XML tag
80      */
81     protected function serializeDispatcher($data, stubXMLStreamWriter $xmlWriter, $tagName = null)
82     {
83         switch (gettype($data)) {
84             case 'NULL':
85                 if (null === $tagName) {
86                     $tagName = 'null';
87                 }
88                 
89                 $xmlWriter->writeStartElement($tagName);
90                 $xmlWriter->writeStartElement('null');
91                 $xmlWriter->writeEndElement();
92                 $xmlWriter->writeEndElement();
93                 break;
94             
95             case 'boolean':
96                 if (null === $tagName) {
97                     $tagName = 'boolean';
98                 }
99                 
100                 $xmlWriter->writeStartElement($tagName);
101                 $xmlWriter->writeText($data === true ? 'true' : 'false');
102                 $xmlWriter->writeEndElement();
103                 break;
104             
105             case 'string':
106             case 'integer':
107             case 'double':
108                 if (null === $tagName) {
109                     $tagName = gettype($data);
110                 }
111                 
112                 $xmlWriter->writeStartElement($tagName);
113                 $xmlWriter->writeText(strval($data));
114                 $xmlWriter->writeEndElement();
115                 break;
116             
117             case 'array':
118                 $this->serializeArray($data, $xmlWriter, $tagName);
119                 break;
120             
121             case 'object':
122                 $this->serializeObject($data, $xmlWriter, $tagName);
123                 break;
124             
125             default:
126                 // nothing to do
127         }
128     }
129
130     /**
131      * serialize an object
132      *
133      * @param  object               $object     object to serialize
134      * @param  stubXMLStreamWriter  $xmlWriter  XML Writer to use
135      * @param  string               $tagName    name of the XML tag
136      */
137     protected function serializeObject($object, stubXMLStreamWriter $xmlWriter, $tagName)
138     {
139         $serializerData = stubXMLSerializerObjectData::fromObject($object);
140         $xmlWriter->writeStartElement($serializerData->getTagName($tagName));
141         $strategy = $serializerData->getStrategy($this->opts[self::OPT_STRATEGY]);
142         foreach ($serializerData->getProperties() as $propertyName => $propertyData) {
143             $this->handle($object->$propertyName, $xmlWriter, $propertyData, ($strategy & self::STRATEGY_PROPS));
144         }
145         
146         foreach ($serializerData->getMethods() as $methodName => $methodData) {
147             $this->handle($object->$methodName(), $xmlWriter, $methodData, ($strategy & self::STRATEGY_METHODS));
148         }
149         
150         $xmlWriter->writeEndElement();
151     }
152
153     /**
154      * serializes given value with instructions from $data
155      *
156      * @param  mixed                               $value          the value to serialize
157      * @param  stubXMLStreamWriter                 $xmlWriter      XML Writer to use
158      * @param  array<string,array<string,scalar>>  $data           instructions on how to serialize
159      * @param  int                                 $mustSerialize  whether the element must be serialized or not
160      */
161     protected function handle($value, stubXMLStreamWriter $xmlWriter, array $data, $mustSerialize)
162     {
163         switch ($data['type']) {
164             case 'attribute':
165                 if ('' === (string) $value && true === $data['shouldSkipEmpty']) {
166                     return;
167                 }
168                 
169                 $xmlWriter->writeAttribute($data['attributeName'], (string) $value);
170                 break;
171             
172             case 'fragment':
173                 if (null != $data['tagName']) {
174                     $xmlWriter->writeStartElement($data['tagName']);
175                     $xmlWriter->writeXmlFragment($value);
176                     $xmlWriter->writeEndElement();
177                 } else {
178                     $xmlWriter->writeXmlFragment($value);
179                 }
180                 break;
181             
182             default:
183                 if (false === $data['mustSerialize'] && 0 === $mustSerialize) {
184                     return;
185                 }
186                 
187                 if (is_array($value) === true) {
188                     $this->serializeArray($value, $xmlWriter, $data['tagName'], $data['elementName']);
189                 } else {
190                     $this->serializeDispatcher($value, $xmlWriter, $data['tagName']);
191                 }
192         }
193     }
194
195     /**
196      * serialize an array
197      *
198      * @param  array                $array       array to serialize
199      * @param  stubXMLStreamWriter  $xmlWriter   XML Writer to use
200      * @param  string               $tagName     'root' name for the array
201      * @param  string               $defaultTag  The default tag for indexed arrays
202      */
203     protected function serializeArray($array, stubXMLStreamWriter $xmlWriter, $tagName, $defaultTag = null)
204     {
205         if (null === $tagName) {
206             $tagName = 'array';
207         }
208         
209         if (false !== $tagName) {
210             $xmlWriter->writeStartElement($tagName);
211         }
212         
213         foreach ($array as $key => $value) {
214             if (is_int($key) === true) {
215                 if (null === $defaultTag) {
216                     $this->serializeDispatcher($value, $xmlWriter);
217                 } else {
218                     $this->serializeDispatcher($value, $xmlWriter, $defaultTag);
219                 }
220             } else {
221                 $this->serializeDispatcher($value, $xmlWriter, $key);
222             }
223         }
224         
225         if (false !== $tagName) {
226             $xmlWriter->writeEndElement();
227         }
228     }
229 }
230 ?>
Note: See TracBrowser for help on using the browser.