1
1
<?php
2
-
3
2
namespace Spatie \ArrayToXml ;
4
-
5
3
use DOMElement ;
6
4
use DOMDocument ;
7
5
use DOMException ;
8
-
6
+ use DOMImplementation ;
9
7
class ArrayToXml
10
8
{
11
9
/**
@@ -14,21 +12,12 @@ class ArrayToXml
14
12
* @var DOMDocument
15
13
*/
16
14
protected $ document ;
17
-
18
15
/**
19
16
* Set to enable replacing space with underscore.
20
17
*
21
18
* @var bool
22
19
*/
23
20
protected $ replaceSpacesByUnderScoresInKeyNames = true ;
24
-
25
- /**
26
- * Prefix for the tags with numeric names.
27
- *
28
- * @var string
29
- */
30
- protected $ numericTagNamePrefix = 'numeric_ ' ;
31
-
32
21
/**
33
22
* Construct a new instance.
34
23
*
@@ -37,48 +26,44 @@ class ArrayToXml
37
26
* @param bool $replaceSpacesByUnderScoresInKeyNames
38
27
* @param string $xmlEncoding
39
28
* @param string $xmlVersion
29
+ * @param array $docTypeArray
40
30
*
41
31
* @throws DOMException
42
32
*/
43
- public function __construct (array $ array , $ rootElement = '' , $ replaceSpacesByUnderScoresInKeyNames = true , $ xmlEncoding = null , $ xmlVersion = '1.0 ' )
33
+ public function __construct (array $ array , $ rootElement = '' , $ replaceSpacesByUnderScoresInKeyNames = true , $ xmlEncoding = null , $ xmlVersion = '1.0 ' , $ docTypeArray = [] )
44
34
{
45
35
$ this ->document = new DOMDocument ($ xmlVersion , $ xmlEncoding );
46
36
$ this ->replaceSpacesByUnderScoresInKeyNames = $ replaceSpacesByUnderScoresInKeyNames ;
47
-
48
37
if ($ this ->isArrayAllKeySequential ($ array ) && ! empty ($ array )) {
49
38
throw new DOMException ('Invalid Character Error ' );
50
39
}
51
-
40
+ if (! empty ($ docTypeArray )) {
41
+ $ docType = $ this ->createDocType ($ docTypeArray );
42
+ $ this ->document ->appendChild ($ docType );
43
+ }
52
44
$ root = $ this ->createRootElement ($ rootElement );
53
-
54
45
$ this ->document ->appendChild ($ root );
55
-
56
46
$ this ->convertElement ($ root , $ array );
57
47
}
58
48
59
- public function setNumericTagNamePrefix (string $ prefix )
60
- {
61
- $ this ->numericTagNamePrefix = $ prefix ;
62
- }
63
-
64
49
/**
65
50
* Convert the given array to an xml string.
66
51
*
67
52
* @param string[] $array
68
- * @param string|array $rootElement
53
+ * @param string $rootElementName
69
54
* @param bool $replaceSpacesByUnderScoresInKeyNames
70
55
* @param string $xmlEncoding
71
56
* @param string $xmlVersion
57
+ * @param array $docTypeArray
72
58
*
73
59
* @return string
60
+ * @throws DOMException
74
61
*/
75
- public static function convert (array $ array , $ rootElement = '' , $ replaceSpacesByUnderScoresInKeyNames = true , $ xmlEncoding = null , $ xmlVersion = '1.0 ' )
62
+ public static function convert (array $ array , $ rootElementName = '' , $ replaceSpacesByUnderScoresInKeyNames = true , $ xmlEncoding = null , $ xmlVersion = '1.0 ' , $ docTypeArray = [] )
76
63
{
77
- $ converter = new static ($ array , $ rootElement , $ replaceSpacesByUnderScoresInKeyNames , $ xmlEncoding , $ xmlVersion );
78
-
64
+ $ converter = new static ($ array , $ rootElementName , $ replaceSpacesByUnderScoresInKeyNames , $ xmlEncoding , $ xmlVersion , $ docTypeArray );
79
65
return $ converter ->toXml ();
80
66
}
81
-
82
67
/**
83
68
* Return as XML.
84
69
*
@@ -88,7 +73,6 @@ public function toXml()
88
73
{
89
74
return $ this ->document ->saveXML ();
90
75
}
91
-
92
76
/**
93
77
* Return as DOM object.
94
78
*
@@ -98,7 +82,6 @@ public function toDom()
98
82
{
99
83
return $ this ->document ;
100
84
}
101
-
102
85
/**
103
86
* Parse individual element.
104
87
*
@@ -108,17 +91,10 @@ public function toDom()
108
91
private function convertElement (DOMElement $ element , $ value )
109
92
{
110
93
$ sequential = $ this ->isArrayAllKeySequential ($ value );
111
-
112
94
if (! is_array ($ value )) {
113
- $ value = htmlspecialchars ($ value );
114
-
115
- $ value = $ this ->removeControlCharacters ($ value );
116
-
117
- $ element ->nodeValue = $ value ;
118
-
95
+ $ element ->nodeValue = htmlspecialchars ($ value );
119
96
return ;
120
97
}
121
-
122
98
foreach ($ value as $ key => $ data ) {
123
99
if (! $ sequential ) {
124
100
if (($ key === '_attributes ' ) || ($ key === '@attributes ' )) {
@@ -127,12 +103,6 @@ private function convertElement(DOMElement $element, $value)
127
103
$ element ->nodeValue = htmlspecialchars ($ data );
128
104
} elseif ((($ key === '_cdata ' ) || ($ key === '@cdata ' )) && is_string ($ data )) {
129
105
$ element ->appendChild ($ this ->document ->createCDATASection ($ data ));
130
- } elseif ((($ key === '_mixed ' ) || ($ key === '@mixed ' )) && is_string ($ data )) {
131
- $ fragment = $ this ->document ->createDocumentFragment ();
132
- $ fragment ->appendXML ($ data );
133
- $ element ->appendChild ($ fragment );
134
- } elseif ($ key === '__numeric ' ) {
135
- $ this ->addNumericNode ($ element , $ data );
136
106
} else {
137
107
$ this ->addNode ($ element , $ key , $ data );
138
108
}
@@ -143,20 +113,6 @@ private function convertElement(DOMElement $element, $value)
143
113
}
144
114
}
145
115
}
146
-
147
- /**
148
- * Add node with numeric keys.
149
- *
150
- * @param DOMElement $element
151
- * @param string|string[] $value
152
- */
153
- protected function addNumericNode (DOMElement $ element , $ value )
154
- {
155
- foreach ($ value as $ key => $ item ) {
156
- $ this ->convertElement ($ element , [$ this ->numericTagNamePrefix .$ key => $ value ]);
157
- }
158
- }
159
-
160
116
/**
161
117
* Add node.
162
118
*
@@ -169,12 +125,10 @@ protected function addNode(DOMElement $element, $key, $value)
169
125
if ($ this ->replaceSpacesByUnderScoresInKeyNames ) {
170
126
$ key = str_replace (' ' , '_ ' , $ key );
171
127
}
172
-
173
128
$ child = $ this ->document ->createElement ($ key );
174
129
$ element ->appendChild ($ child );
175
130
$ this ->convertElement ($ child , $ value );
176
131
}
177
-
178
132
/**
179
133
* Add collection node.
180
134
*
@@ -187,15 +141,12 @@ protected function addCollectionNode(DOMElement $element, $value)
187
141
{
188
142
if ($ element ->childNodes ->length === 0 && $ element ->attributes ->length === 0 ) {
189
143
$ this ->convertElement ($ element , $ value );
190
-
191
144
return ;
192
145
}
193
-
194
- $ child = $ this ->document ->createElement ($ element ->tagName );
146
+ $ child = new DOMElement ($ element ->tagName );
195
147
$ element ->parentNode ->appendChild ($ child );
196
148
$ this ->convertElement ($ child , $ value );
197
149
}
198
-
199
150
/**
200
151
* Add sequential node.
201
152
*
@@ -208,15 +159,12 @@ protected function addSequentialNode(DOMElement $element, $value)
208
159
{
209
160
if (empty ($ element ->nodeValue )) {
210
161
$ element ->nodeValue = htmlspecialchars ($ value );
211
-
212
162
return ;
213
163
}
214
-
215
164
$ child = new DOMElement ($ element ->tagName );
216
165
$ child ->nodeValue = htmlspecialchars ($ value );
217
166
$ element ->parentNode ->appendChild ($ child );
218
167
}
219
-
220
168
/**
221
169
* Check if array are all sequential.
222
170
*
@@ -229,18 +177,11 @@ protected function isArrayAllKeySequential($value)
229
177
if (! is_array ($ value )) {
230
178
return false ;
231
179
}
232
-
233
180
if (count ($ value ) <= 0 ) {
234
181
return true ;
235
182
}
236
-
237
- if (\key ($ value ) === '__numeric ' ) {
238
- return false ;
239
- }
240
-
241
183
return array_unique (array_map ('is_int ' , array_keys ($ value ))) === [true ];
242
184
}
243
-
244
185
/**
245
186
* Add attributes.
246
187
*
@@ -253,7 +194,6 @@ protected function addAttributes($element, $data)
253
194
$ element ->setAttribute ($ attrKey , $ attrVal );
254
195
}
255
196
}
256
-
257
197
/**
258
198
* Create the root element.
259
199
*
@@ -264,31 +204,27 @@ protected function createRootElement($rootElement)
264
204
{
265
205
if (is_string ($ rootElement )) {
266
206
$ rootElementName = $ rootElement ?: 'root ' ;
267
-
268
207
return $ this ->document ->createElement ($ rootElementName );
269
208
}
270
-
271
209
$ rootElementName = $ rootElement ['rootElementName ' ] ?? 'root ' ;
272
-
273
210
$ element = $ this ->document ->createElement ($ rootElementName );
274
-
275
211
foreach ($ rootElement as $ key => $ value ) {
276
212
if ($ key !== '_attributes ' && $ key !== '@attributes ' ) {
277
213
continue ;
278
214
}
279
-
280
215
$ this ->addAttributes ($ element , $ rootElement [$ key ]);
281
216
}
282
-
283
217
return $ element ;
284
218
}
285
-
286
219
/**
287
- * @param $valuet
288
- * @return string
220
+ * Pass in an array of elements to set the doctype of the XML.
221
+ * @param $docTypeArray
222
+ *
223
+ * @return \DOMDocumentType
289
224
*/
290
- protected function removeControlCharacters ( $ value )
225
+ protected function createDocType ( $ docTypeArray )
291
226
{
292
- return preg_replace ('/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/ ' , '' , $ value );
227
+ $ implementation = new DOMImplementation ();
228
+ return $ implementation ->createDocumentType ($ docTypeArray [0 ], $ docTypeArray [1 ], $ docTypeArray [2 ]);
293
229
}
294
- }
230
+ }
0 commit comments