[ Index ]

PHP Cross Reference of YOURLS

title

Body

[close]

/includes/vendor/spatie/array-to-xml/src/ -> ArrayToXml.php (source)

   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  }


Generated: Tue Jan 21 05:10:11 2025 Cross-referenced by PHPXref 0.7.1