11<?php
2-
32namespace Spatie \ArrayToXml ;
4-
53use DOMElement ;
64use DOMDocument ;
75use DOMException ;
8-
6+ use DOMImplementation ;
97class ArrayToXml
108{
119 /**
@@ -14,21 +12,12 @@ class ArrayToXml
1412 * @var DOMDocument
1513 */
1614 protected $ document ;
17-
1815 /**
1916 * Set to enable replacing space with underscore.
2017 *
2118 * @var bool
2219 */
2320 protected $ replaceSpacesByUnderScoresInKeyNames = true ;
24-
25- /**
26- * Prefix for the tags with numeric names.
27- *
28- * @var string
29- */
30- protected $ numericTagNamePrefix = 'numeric_ ' ;
31-
3221 /**
3322 * Construct a new instance.
3423 *
@@ -37,48 +26,44 @@ class ArrayToXml
3726 * @param bool $replaceSpacesByUnderScoresInKeyNames
3827 * @param string $xmlEncoding
3928 * @param string $xmlVersion
29+ * @param array $docTypeArray
4030 *
4131 * @throws DOMException
4232 */
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 = [] )
4434 {
4535 $ this ->document = new DOMDocument ($ xmlVersion , $ xmlEncoding );
4636 $ this ->replaceSpacesByUnderScoresInKeyNames = $ replaceSpacesByUnderScoresInKeyNames ;
47-
4837 if ($ this ->isArrayAllKeySequential ($ array ) && ! empty ($ array )) {
4938 throw new DOMException ('Invalid Character Error ' );
5039 }
51-
40+ if (! empty ($ docTypeArray )) {
41+ $ docType = $ this ->createDocType ($ docTypeArray );
42+ $ this ->document ->appendChild ($ docType );
43+ }
5244 $ root = $ this ->createRootElement ($ rootElement );
53-
5445 $ this ->document ->appendChild ($ root );
55-
5646 $ this ->convertElement ($ root , $ array );
5747 }
5848
59- public function setNumericTagNamePrefix (string $ prefix )
60- {
61- $ this ->numericTagNamePrefix = $ prefix ;
62- }
63-
6449 /**
6550 * Convert the given array to an xml string.
6651 *
6752 * @param string[] $array
68- * @param string|array $rootElement
53+ * @param string $rootElementName
6954 * @param bool $replaceSpacesByUnderScoresInKeyNames
7055 * @param string $xmlEncoding
7156 * @param string $xmlVersion
57+ * @param array $docTypeArray
7258 *
7359 * @return string
60+ * @throws DOMException
7461 */
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 = [] )
7663 {
77- $ converter = new static ($ array , $ rootElement , $ replaceSpacesByUnderScoresInKeyNames , $ xmlEncoding , $ xmlVersion );
78-
64+ $ converter = new static ($ array , $ rootElementName , $ replaceSpacesByUnderScoresInKeyNames , $ xmlEncoding , $ xmlVersion , $ docTypeArray );
7965 return $ converter ->toXml ();
8066 }
81-
8267 /**
8368 * Return as XML.
8469 *
@@ -88,7 +73,6 @@ public function toXml()
8873 {
8974 return $ this ->document ->saveXML ();
9075 }
91-
9276 /**
9377 * Return as DOM object.
9478 *
@@ -98,7 +82,6 @@ public function toDom()
9882 {
9983 return $ this ->document ;
10084 }
101-
10285 /**
10386 * Parse individual element.
10487 *
@@ -108,17 +91,10 @@ public function toDom()
10891 private function convertElement (DOMElement $ element , $ value )
10992 {
11093 $ sequential = $ this ->isArrayAllKeySequential ($ value );
111-
11294 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 );
11996 return ;
12097 }
121-
12298 foreach ($ value as $ key => $ data ) {
12399 if (! $ sequential ) {
124100 if (($ key === '_attributes ' ) || ($ key === '@attributes ' )) {
@@ -127,12 +103,6 @@ private function convertElement(DOMElement $element, $value)
127103 $ element ->nodeValue = htmlspecialchars ($ data );
128104 } elseif ((($ key === '_cdata ' ) || ($ key === '@cdata ' )) && is_string ($ data )) {
129105 $ 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 );
136106 } else {
137107 $ this ->addNode ($ element , $ key , $ data );
138108 }
@@ -143,20 +113,6 @@ private function convertElement(DOMElement $element, $value)
143113 }
144114 }
145115 }
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-
160116 /**
161117 * Add node.
162118 *
@@ -169,12 +125,10 @@ protected function addNode(DOMElement $element, $key, $value)
169125 if ($ this ->replaceSpacesByUnderScoresInKeyNames ) {
170126 $ key = str_replace (' ' , '_ ' , $ key );
171127 }
172-
173128 $ child = $ this ->document ->createElement ($ key );
174129 $ element ->appendChild ($ child );
175130 $ this ->convertElement ($ child , $ value );
176131 }
177-
178132 /**
179133 * Add collection node.
180134 *
@@ -187,15 +141,12 @@ protected function addCollectionNode(DOMElement $element, $value)
187141 {
188142 if ($ element ->childNodes ->length === 0 && $ element ->attributes ->length === 0 ) {
189143 $ this ->convertElement ($ element , $ value );
190-
191144 return ;
192145 }
193-
194- $ child = $ this ->document ->createElement ($ element ->tagName );
146+ $ child = new DOMElement ($ element ->tagName );
195147 $ element ->parentNode ->appendChild ($ child );
196148 $ this ->convertElement ($ child , $ value );
197149 }
198-
199150 /**
200151 * Add sequential node.
201152 *
@@ -208,15 +159,12 @@ protected function addSequentialNode(DOMElement $element, $value)
208159 {
209160 if (empty ($ element ->nodeValue )) {
210161 $ element ->nodeValue = htmlspecialchars ($ value );
211-
212162 return ;
213163 }
214-
215164 $ child = new DOMElement ($ element ->tagName );
216165 $ child ->nodeValue = htmlspecialchars ($ value );
217166 $ element ->parentNode ->appendChild ($ child );
218167 }
219-
220168 /**
221169 * Check if array are all sequential.
222170 *
@@ -229,18 +177,11 @@ protected function isArrayAllKeySequential($value)
229177 if (! is_array ($ value )) {
230178 return false ;
231179 }
232-
233180 if (count ($ value ) <= 0 ) {
234181 return true ;
235182 }
236-
237- if (\key ($ value ) === '__numeric ' ) {
238- return false ;
239- }
240-
241183 return array_unique (array_map ('is_int ' , array_keys ($ value ))) === [true ];
242184 }
243-
244185 /**
245186 * Add attributes.
246187 *
@@ -253,7 +194,6 @@ protected function addAttributes($element, $data)
253194 $ element ->setAttribute ($ attrKey , $ attrVal );
254195 }
255196 }
256-
257197 /**
258198 * Create the root element.
259199 *
@@ -264,31 +204,27 @@ protected function createRootElement($rootElement)
264204 {
265205 if (is_string ($ rootElement )) {
266206 $ rootElementName = $ rootElement ?: 'root ' ;
267-
268207 return $ this ->document ->createElement ($ rootElementName );
269208 }
270-
271209 $ rootElementName = $ rootElement ['rootElementName ' ] ?? 'root ' ;
272-
273210 $ element = $ this ->document ->createElement ($ rootElementName );
274-
275211 foreach ($ rootElement as $ key => $ value ) {
276212 if ($ key !== '_attributes ' && $ key !== '@attributes ' ) {
277213 continue ;
278214 }
279-
280215 $ this ->addAttributes ($ element , $ rootElement [$ key ]);
281216 }
282-
283217 return $ element ;
284218 }
285-
286219 /**
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
289224 */
290- protected function removeControlCharacters ( $ value )
225+ protected function createDocType ( $ docTypeArray )
291226 {
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 ]);
293229 }
294- }
230+ }
0 commit comments