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. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
Element.php
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 }