[ Index ] |
PHP Cross Reference of YOURLS |
[Summary view] [Print] [Text view]
1 <?php 2 3 namespace Spatie\ArrayToXml; 4 5 use DOMDocument; 6 use DOMElement; 7 use DOMException; 8 use Exception; 9 10 class ArrayToXml 11 { 12 protected $document; 13 14 protected $replaceSpacesByUnderScoresInKeyNames = true; 15 16 protected $addXmlDeclaration = true; 17 18 protected $numericTagNamePrefix = 'numeric_'; 19 20 public function __construct( 21 array $array, 22 $rootElement = '', 23 $replaceSpacesByUnderScoresInKeyNames = true, 24 $xmlEncoding = null, 25 $xmlVersion = '1.0', 26 $domProperties = [], 27 $xmlStandalone = null 28 ) { 29 $this->document = new DOMDocument($xmlVersion, $xmlEncoding ?? ''); 30 31 if (! is_null($xmlStandalone)) { 32 $this->document->xmlStandalone = $xmlStandalone; 33 } 34 35 if (! empty($domProperties)) { 36 $this->setDomProperties($domProperties); 37 } 38 39 $this->replaceSpacesByUnderScoresInKeyNames = $replaceSpacesByUnderScoresInKeyNames; 40 41 if (! empty($array) && $this->isArrayAllKeySequential($array)) { 42 throw new DOMException('Invalid Character Error'); 43 } 44 45 $root = $this->createRootElement($rootElement); 46 47 $this->document->appendChild($root); 48 49 $this->convertElement($root, $array); 50 } 51 52 public function setNumericTagNamePrefix(string $prefix) 53 { 54 $this->numericTagNamePrefix = $prefix; 55 } 56 57 public static function convert( 58 array $array, 59 $rootElement = '', 60 bool $replaceSpacesByUnderScoresInKeyNames = true, 61 string $xmlEncoding = null, 62 string $xmlVersion = '1.0', 63 array $domProperties = [], 64 bool $xmlStandalone = null 65 ) { 66 $converter = new static( 67 $array, 68 $rootElement, 69 $replaceSpacesByUnderScoresInKeyNames, 70 $xmlEncoding, 71 $xmlVersion, 72 $domProperties, 73 $xmlStandalone 74 ); 75 76 return $converter->toXml(); 77 } 78 79 public function toXml(): string 80 { 81 return $this->addXmlDeclaration 82 ? $this->document->saveXML() 83 : $this->document->saveXml($this->document->documentElement); 84 } 85 86 public function toDom(): DOMDocument 87 { 88 return $this->document; 89 } 90 91 protected function ensureValidDomProperties(array $domProperties) 92 { 93 foreach ($domProperties as $key => $value) { 94 if (! property_exists($this->document, $key)) { 95 throw new Exception("{$key} is not a valid property of DOMDocument"); 96 } 97 } 98 } 99 100 public function setDomProperties(array $domProperties) 101 { 102 $this->ensureValidDomProperties($domProperties); 103 104 foreach ($domProperties as $key => $value) { 105 $this->document->{$key} = $value; 106 } 107 108 return $this; 109 } 110 111 public function prettify() 112 { 113 $this->document->preserveWhiteSpace = false; 114 $this->document->formatOutput = true; 115 116 return $this; 117 } 118 119 public function dropXmlDeclaration() 120 { 121 $this->addXmlDeclaration = false; 122 123 return $this; 124 } 125 126 public function addProcessingInstruction($target, $data) 127 { 128 $elements = $this->document->getElementsByTagName('*'); 129 130 $rootElement = $elements->count() > 0 ? $elements->item(0) : null; 131 132 $processingInstruction = $this->document->createProcessingInstruction($target, $data); 133 134 $this->document->insertBefore($processingInstruction, $rootElement); 135 136 return $this; 137 } 138 139 private function convertElement(DOMElement $element, $value) 140 { 141 $sequential = $this->isArrayAllKeySequential($value); 142 143 if (! is_array($value)) { 144 $value = htmlspecialchars($value ?? ''); 145 146 $value = $this->removeControlCharacters($value); 147 148 $element->nodeValue = $value; 149 150 return; 151 } 152 153 foreach ($value as $key => $data) { 154 if (! $sequential) { 155 if (($key === '_attributes') || ($key === '@attributes')) { 156 $this->addAttributes($element, $data); 157 } elseif ((($key === '_value') || ($key === '@value')) && is_string($data)) { 158 $element->nodeValue = htmlspecialchars($data); 159 } elseif ((($key === '_cdata') || ($key === '@cdata')) && is_string($data)) { 160 $element->appendChild($this->document->createCDATASection($data)); 161 } elseif ((($key === '_mixed') || ($key === '@mixed')) && is_string($data)) { 162 $fragment = $this->document->createDocumentFragment(); 163 $fragment->appendXML($data); 164 $element->appendChild($fragment); 165 } elseif ($key === '__numeric') { 166 $this->addNumericNode($element, $data); 167 } elseif (substr($key, 0, 9) === '__custom:') { 168 $this->addNode($element, str_replace('\:', ':', preg_split('/(?<!\\\):/', $key)[1]), $data); 169 } else { 170 $this->addNode($element, $key, $data); 171 } 172 } elseif (is_array($data)) { 173 $this->addCollectionNode($element, $data); 174 } else { 175 $this->addSequentialNode($element, $data); 176 } 177 } 178 } 179 180 protected function addNumericNode(DOMElement $element, $value) 181 { 182 foreach ($value as $key => $item) { 183 $this->convertElement($element, [$this->numericTagNamePrefix.$key => $item]); 184 } 185 } 186 187 protected function addNode(DOMElement $element, $key, $value) 188 { 189 if ($this->replaceSpacesByUnderScoresInKeyNames) { 190 $key = str_replace(' ', '_', $key); 191 } 192 193 $child = $this->document->createElement($key); 194 $element->appendChild($child); 195 $this->convertElement($child, $value); 196 } 197 198 protected function addCollectionNode(DOMElement $element, $value) 199 { 200 if ($element->childNodes->length === 0 && $element->attributes->length === 0) { 201 $this->convertElement($element, $value); 202 203 return; 204 } 205 206 $child = $this->document->createElement($element->tagName); 207 $element->parentNode->appendChild($child); 208 $this->convertElement($child, $value); 209 } 210 211 protected function addSequentialNode(DOMElement $element, $value) 212 { 213 if (empty($element->nodeValue) && ! is_numeric($element->nodeValue)) { 214 $element->nodeValue = htmlspecialchars($value); 215 216 return; 217 } 218 219 $child = $this->document->createElement($element->tagName); 220 $child->nodeValue = htmlspecialchars($value); 221 $element->parentNode->appendChild($child); 222 } 223 224 protected function isArrayAllKeySequential($value) 225 { 226 if (! is_array($value)) { 227 return false; 228 } 229 230 if (count($value) <= 0) { 231 return true; 232 } 233 234 if (\key($value) === '__numeric') { 235 return false; 236 } 237 238 return array_unique(array_map('is_int', array_keys($value))) === [true]; 239 } 240 241 protected function addAttributes(DOMElement $element, array $data) 242 { 243 foreach ($data as $attrKey => $attrVal) { 244 $element->setAttribute($attrKey, $attrVal ?? ''); 245 } 246 } 247 248 protected function createRootElement($rootElement): DOMElement 249 { 250 if (is_string($rootElement)) { 251 $rootElementName = $rootElement ?: 'root'; 252 253 return $this->document->createElement($rootElementName); 254 } 255 256 $rootElementName = $rootElement['rootElementName'] ?? 'root'; 257 258 $element = $this->document->createElement($rootElementName); 259 260 foreach ($rootElement as $key => $value) { 261 if ($key !== '_attributes' && $key !== '@attributes') { 262 continue; 263 } 264 265 $this->addAttributes($element, $rootElement[$key]); 266 } 267 268 return $element; 269 } 270 271 protected function removeControlCharacters(string $value): string 272 { 273 return preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/', '', $value); 274 } 275 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Jan 21 05:10:11 2025 | Cross-referenced by PHPXref 0.7.1 |