Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

Element.php

Zuletzt modifiziert: 02.04.2025, 15:03 - Dateigröße: 10.59 KiB


001  <?php declare(strict_types=1);
002   
003  /**
004  * @package   s9e\SweetDOM
005  * @copyright Copyright (c) 2019-2021 The s9e authors
006  * @license   http://www.opensource.org/licenses/mit-license.php The MIT License
007  */
008  namespace s9e\SweetDOM;
009   
010  use BadMethodCallException;
011  use DOMElement;
012  use DOMException;
013  use DOMNode;
014  use DOMNodeList;
015  use DOMText;
016   
017  /**
018  * @method self appendElement(string $nodeName, $text = '')
019  * @method self appendElementSibling(string $nodeName, $text = '')
020  * @method DOMText appendText(string $text)
021  * @method DOMText appendTextSibling(string $text)
022  * @method self appendXslApplyTemplates(string $select = null)
023  * @method self appendXslApplyTemplatesSibling(string $select = null)
024  * @method self appendXslAttribute(string $name, string $text = '')
025  * @method self appendXslAttributeSibling(string $name, string $text = '')
026  * @method self appendXslChoose()
027  * @method self appendXslChooseSibling()
028  * @method self appendXslComment(string $text = '')
029  * @method self appendXslCommentSibling(string $text = '')
030  * @method self appendXslCopyOf(string $select)
031  * @method self appendXslCopyOfSibling(string $select)
032  * @method self appendXslIf(string $test, string $text = '')
033  * @method self appendXslIfSibling(string $test, string $text = '')
034  * @method self appendXslOtherwise(string $text = '')
035  * @method self appendXslOtherwiseSibling(string $text = '')
036  * @method self appendXslText(string $text = '')
037  * @method self appendXslTextSibling(string $text = '')
038  * @method self appendXslValueOf(string $select)
039  * @method self appendXslValueOfSibling(string $select)
040  * @method self appendXslVariable(string $name, string $select = null)
041  * @method self appendXslVariableSibling(string $name, string $select = null)
042  * @method self appendXslWhen(string $test, string $text = '')
043  * @method self appendXslWhenSibling(string $test, string $text = '')
044  * @method self prependElement(string $nodeName, $text = '')
045  * @method self prependElementSibling(string $nodeName, $text = '')
046  * @method DOMText prependText(string $text)
047  * @method DOMText prependTextSibling(string $text)
048  * @method self prependXslApplyTemplates(string $select = null)
049  * @method self prependXslApplyTemplatesSibling(string $select = null)
050  * @method self prependXslAttribute(string $name, string $text = '')
051  * @method self prependXslAttributeSibling(string $name, string $text = '')
052  * @method self prependXslChoose()
053  * @method self prependXslChooseSibling()
054  * @method self prependXslComment(string $text = '')
055  * @method self prependXslCommentSibling(string $text = '')
056  * @method self prependXslCopyOf(string $select)
057  * @method self prependXslCopyOfSibling(string $select)
058  * @method self prependXslIf(string $test, string $text = '')
059  * @method self prependXslIfSibling(string $test, string $text = '')
060  * @method self prependXslOtherwise(string $text = '')
061  * @method self prependXslOtherwiseSibling(string $text = '')
062  * @method self prependXslText(string $text = '')
063  * @method self prependXslTextSibling(string $text = '')
064  * @method self prependXslValueOf(string $select)
065  * @method self prependXslValueOfSibling(string $select)
066  * @method self prependXslVariable(string $name, string $select = null)
067  * @method self prependXslVariableSibling(string $name, string $select = null)
068  * @method self prependXslWhen(string $test, string $text = '')
069  * @method self prependXslWhenSibling(string $test, string $text = '')
070  * @property Document $ownerDocument
071  */
072  class Element extends DOMElement
073  {
074      public function __call(string $name, array $arguments)
075      {
076          $name      = strtolower($name);
077          $positions = [
078              'append'         => 'beforeend',
079              'appendsibling'  => 'afterend',
080              'prepend'        => 'afterbegin',
081              'prependsibling' => 'beforebegin'
082          ];
083   
084          if (preg_match('(^(append|prepend)xsl(\\w+?)(sibling|)$)', $name, $m))
085          {
086              $localName = $m[2];
087              $where     = $positions[$m[1] . $m[3]];
088   
089              return $this->insertXslElement($where, $localName, $arguments);
090          }
091          if (preg_match('(^(append|prepend)element(sibling|)$)', $name, $m))
092          {
093              $nodeName = $arguments[0];
094              $text     = $arguments[1] ?? '';
095              $where    = $positions[$m[1] . $m[2]];
096   
097              return $this->insertElement($where, $nodeName, $text);
098          }
099          if (preg_match('(^(append|prepend)text(sibling|)$)', $name, $m))
100          {
101              $text  = $arguments[0];
102              $where = $positions[$m[1] . $m[2]];
103   
104              return $this->insertText($where, $text);
105          }
106   
107          throw new BadMethodCallException;
108      }
109   
110      /**
111      * Evaluate and return the result of a given XPath expression using this element as context node
112      *
113      * @param  string  $expr XPath expression
114      * @return mixed
115      */
116      public function evaluate(string $expr)
117      {
118          return $this->ownerDocument->evaluate($expr, $this);
119      }
120   
121      /**
122      * Evaluate and return the first element of a given XPath query using this element as context node
123      *
124      * @param  string       $expr XPath expression
125      * @return DOMNode|null
126      */
127      public function firstOf(string $expr): ?DOMNode
128      {
129          return $this->ownerDocument->firstOf($expr, $this);
130      }
131   
132      /**
133      * Insert given element relative to this element's position
134      *
135      * @param  string     $where   One of 'beforebegin', 'afterbegin', 'beforeend', 'afterend'
136      * @param  DOMElement $element
137      * @return self
138      */
139      public function insertAdjacentElement(string $where, DOMElement $element): self
140      {
141          $this->insertAdjacentNode($where, $element);
142   
143          return $element;
144      }
145   
146      /**
147      * Insert given text relative to this element's position
148      *
149      * @param  string $where One of 'beforebegin', 'afterbegin', 'beforeend', 'afterend'
150      * @param  string $text
151      * @return void
152      */
153      public function insertAdjacentText(string $where, string $text): void
154      {
155          $this->insertText($where, $text);
156      }
157   
158      /**
159      * Insert given XML relative to this element's position
160      *
161      * @param  string $where One of 'beforebegin', 'afterbegin', 'beforeend', 'afterend'
162      * @param  string $xml
163      * @return void
164      */
165      public function insertAdjacentXML(string $where, string $xml): void
166      {
167          $fragment = $this->ownerDocument->createDocumentFragment();
168          $fragment->appendXML($this->addMissingNamespaceDeclarations($xml));
169   
170          $this->insertAdjacentNode($where, $fragment);
171      }
172   
173      /**
174      * Evaluate and return the result of a given XPath query using this element as context node
175      *
176      * @param  string      $expr XPath expression
177      * @return DOMNodeList
178      */
179      public function query(string $expr): DOMNodeList
180      {
181          return $this->ownerDocument->query($expr, $this);
182      }
183   
184      /**
185      * Remove this element from the document
186      *
187      * @return void
188      */
189      public function remove(): void
190      {
191          $this->parentOrThrow()->removeChild($this);
192      }
193   
194      /**
195      * Replace this element with given nodes/text
196      *
197      * @param  DOMNode|string $nodes
198      * @return void
199      */
200      public function replaceWith(...$nodes): void
201      {
202          $parentNode = $this->parentOrThrow(new DOMException('No Modification Allowed Error', DOM_NO_MODIFICATION_ALLOWED_ERR));
203   
204          foreach ($nodes as $node)
205          {
206              if (!($node instanceof DOMNode))
207              {
208                  $node = $this->ownerDocument->createTextNode((string) $node);
209              }
210              $parentNode->insertBefore($node, $this);
211          }
212          $parentNode->removeChild($this);
213      }
214   
215      /**
216      * Add namespace declarations that may be missing in given XML
217      *
218      * @param  string $xml Original XML
219      * @return string      Modified XML
220      */
221      protected function addMissingNamespaceDeclarations(string $xml): string
222      {
223          preg_match_all('(xmlns:\\K[-\\w]++(?==))', $xml, $m);
224          $prefixes = array_flip($m[0]);
225   
226          return preg_replace_callback(
227              '(<([-\\w]++):[^>]*?\\K\\s*/?>)',
228              function ($m) use ($prefixes)
229              {
230                  $return = $m[0];
231                  $prefix = $m[1];
232                  if (!isset($prefixes[$prefix]))
233                  {
234                      $nsURI  = $this->lookupNamespaceURI($prefix);
235                      $return = ' xmlns:' . $prefix . '="' . htmlspecialchars($nsURI, ENT_XML1) . '"' . $return;
236                  }
237   
238                  return $return;
239              },
240              $xml
241          );
242      }
243   
244      /**
245      * Insert given node relative to this element's position
246      *
247      * @param  string  $where One of 'beforebegin', 'afterbegin', 'beforeend', 'afterend'
248      * @param  DOMNode $node
249      * @return void
250      */
251      protected function insertAdjacentNode(string $where, DOMNode $node): void
252      {
253          switch (strtolower($where))
254          {
255              case 'afterbegin':
256                  $this->insertBefore($node, $this->firstChild);
257                  break;
258   
259              case 'afterend':
260                  if (isset($this->parentNode))
261                  {
262                      $this->parentNode->insertBefore($node, $this->nextSibling);
263                  }
264                  break;
265   
266              case 'beforebegin':
267                  if (isset($this->parentNode))
268                  {
269                      $this->parentNode->insertBefore($node, $this);
270                  }
271                  break;
272   
273              case 'beforeend':
274                  $this->appendChild($node);
275                  break;
276   
277              default:
278                  throw new DOMException("'$where' is not one of 'beforebegin', 'afterbegin', 'beforeend', or 'afterend'", DOM_SYNTAX_ERR);
279          }
280      }
281   
282      /**
283      * Create and insert an element at given position
284      *
285      * @param  string $where    One of 'beforebegin', 'afterbegin', 'beforeend', 'afterend'
286      * @param  string $nodeName Element's nodeName
287      * @param  string $text     Text content
288      * @return self
289      */
290      protected function insertElement(string $where, string $nodeName, string $text): self
291      {
292          $text = htmlspecialchars($text, ENT_NOQUOTES);
293          $pos  = strpos($nodeName, ':');
294          if ($pos === false)
295          {
296              $element = $this->ownerDocument->createElement($nodeName, $text);
297          }
298          else
299          {
300              $prefix       = substr($nodeName, 0, $pos);
301              $namespaceURI = $this->ownerDocument->lookupNamespaceURI($prefix);
302              $element      = $this->ownerDocument->createElementNS($namespaceURI, $nodeName, $text);
303          }
304   
305          return $this->insertAdjacentElement($where, $element);
306      }
307   
308      /**
309      * Insert given text relative to this element's position
310      *
311      * @param  string  $where One of 'beforebegin', 'afterbegin', 'beforeend', 'afterend'
312      * @param  string  $text
313      * @return DOMText
314      */
315      protected function insertText(string $where, string $text): DOMText
316      {
317          $node = $this->ownerDocument->createTextNode($text);
318          $this->insertAdjacentNode($where, $node);
319   
320          return $node;
321      }
322   
323      /**
324      * Create and insert an XSL element at given position
325      *
326      * @param  string $where     One of 'beforebegin', 'afterbegin', 'beforeend', 'afterend'
327      * @param  string $localName Element's localName
328      * @param  array  $arguments Arguments passed to the Document::create* function
329      * @return self
330      */
331      protected function insertXslElement(string $where, string $localName, array $arguments): self
332      {
333          $callback = [$this->ownerDocument, 'createXsl' . ucfirst($localName)];
334          if (!is_callable($callback))
335          {
336              throw new BadMethodCallException;
337          }
338   
339          $element = call_user_func_array($callback, $arguments);
340   
341          return $this->insertAdjacentElement($where, $element);
342      }
343   
344      /**
345      * Return this element's parent element if available, or throw an exception
346      *
347      * @param  DOMException $previous Previous exception
348      * @return DOMNode
349      */
350      protected function parentOrThrow(DOMException $previous = null): DOMNode
351      {
352          if (isset($this->parentNode))
353          {
354              return $this->parentNode;
355          }
356   
357          throw new DOMException('Not Found Error', DOM_NOT_FOUND_ERR, $previous);
358      }
359  }