-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathXmlDeserializer.php
209 lines (181 loc) · 6.5 KB
/
XmlDeserializer.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
<?php
/**
* Copyright (C) 2014, Some right reserved.
* @author Kacper "Kadet" Donat <[email protected]>
* @license http://creativecommons.org/licenses/by-sa/4.0/legalcode CC BY-SA
*
* Contact with author:
* Xmpp: [email protected]
* E-mail: [email protected]
*
* From Kadet with love.
*/
namespace Kadet\XmlSerializer;
require_once 'functions.php';
class XmlDeserializer
{
/**
* @var \DOMDocument
*/
private $_document;
/**
* Default DAO
* @var string
*/
public $dao = 'stdClass';
public function __construct()
{
$this->_document = new \DOMDocument();
$this->_document->formatOutput = true;
$this->_document->encoding = 'utf-8';
$this->_document->preserveWhiteSpace = false;
}
/**
* Deserializes XML node to object.
*
* @param \DOMElement $node XML element to be deserialized.
* @param null|string $class Forced DAO class for object.
*
* @internal param null|object|string $object Forced object or class.
*
* @return object
*/
private function _deserializeObject(\DOMElement $node, $class = null)
{
if (!class_exists($class)) {
$class = $node->getAttributeNS('urn:kadet:serializer', 'type');
if (empty($class)) $class = $this->dao;
}
if (is_subclass_of($class, 'Kadet\\XmlSerializer\\XmlSerializable'))
return $class::fromXml($node, $this);
$object = new $class;
$reflection = new \ReflectionObject($object);
$table = array();
foreach ($reflection->getProperties() as $property) {
$property->setAccessible(true);
$annotations = getAnnotations($property->getDocComment());
if (isset($annotations['xml-skip'])) continue;
if (isset($annotations['xml-attrib'])) {
$name = !empty($annotations['xml-attrib']) ? $annotations['xml-attrib'] : $property->getName();
$table['attrib'][$name] = $property;
} else {
$name = !empty($annotations['xml-tag']) ? $annotations['xml-tag'] : $property->getName();
$table['child'][$name] = $property;
}
}
foreach ($node->attributes as $attribute) {
if (isset($table['attrib'][$attribute->nodeName])) {
$table['attrib'][$attribute->nodeName]->setValue($object, $attribute->nodeValue);
if (!$table['attrib'][$attribute->nodeName]->isPublic())
$table['attrib'][$attribute->nodeName]->setAccessible(false);
}
}
foreach ($node->childNodes as $child) {
if (isset($table['child'][$child->nodeName])) {
$table['child'][$child->nodeName]->setValue($object, $this->deserializeElement($child));
if (!$table['child'][$child->nodeName]->isPublic())
$table['child'][$child->nodeName]->setAccessible(false);
} elseif ($child instanceof \DOMElement) {
$object->{$child->nodeName} = $this->deserializeElement($child);
}
}
return $object;
}
/**
* Deserializes XML node.
*
* @param \DOMElement $node Node to deserialize.
* @param null|string $class Forced DAO class for object.
*
* @return array|bool|float|int|object|string
*/
public function deserializeElement(\DOMElement $node, $class = null)
{
$type = $node->getAttributeNS('urn:kadet:serializer', 'type');
$hasAttributes = false;
foreach($node->attributes as $attribute)
if(strpos($attribute->nodeName, ':') === false)
$hasAttributes = true;
if ($type == 'array')
return $this->_deserializeArray($node);
elseif (class_exists($type) || $node->firstChild instanceof \DOMElement || $hasAttributes)
return $this->_deserializeObject($node, $class);
else
return $this->_deserializeVar($node);
}
/**
* Deserializes XML string.
*
* @param string $xml String that contains xml to deserialize.
* @param null|string $class Forced DAO class for object.
*
* @return array|bool|float|int|null|string
*/
public function deserializeString($xml, $class = null)
{
$this->_document->loadXML($xml);
return $this->_deserialize($class);
}
/**
* Deserializes XML file.
*
* @param string $file Path to file.
* @param null|string $class Forced DAO class for object.
*
* @return array|bool|float|int|null|string
*/
public function deserializeFile($file, $class = null)
{
$this->_document->load($file);
return $this->_deserialize($class);
}
/**
* Deserializes array from XML node.
*
* @param \DOMElement $node Node to be deserialized.
*
* @return array Deserialized array.
*/
private function _deserializeArray(\DOMElement $node)
{
$array = array();
foreach ($node->childNodes as $element)
if($element instanceof \DOMElement)
$array[$element->getAttributeNS('urn:kadet:serializer', 'key')] = $this->deserializeElement($element);
return $array;
}
/**
* Deserializes scalar value from XML node.
*
* @param \DOMElement $node Node to be deserialized.
*
* @return bool|float|int|string
*/
private function _deserializeVar(\DOMElement $node)
{
switch ($node->getAttributeNS('urn:kadet:serializer', 'type')) {
case 'double':
return doubleval($node->nodeValue);
case 'string':
return strval($node->nodeValue);
case 'integer':
return intval($node->nodeValue);
case 'boolean':
return $node->nodeValue == 'false' ? false : (bool)($node->nodeValue);
default:
return $node->nodeValue;
}
}
/**
* Deserialization helper.
*
* @param null|string $class Forced DAO class for object.
* @return array|bool|float|int|null|string
*/
private function _deserialize($class = null)
{
if ($this->_document->documentElement->hasAttributeNS('urn:kadet:serializer', 'dao'))
$this->dao = $this->_document->documentElement->getAttributeNS('urn:kadet:serializer', 'dao');
return $this->deserializeElement($this->_document->documentElement, $class);
}
}