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 |
OptimizeChoose.php
001 <?php
002
003 /**
004 * @package s9e\TextFormatter
005 * @copyright Copyright (c) 2010-2022 The s9e authors
006 * @license http://www.opensource.org/licenses/mit-license.php The MIT License
007 */
008 namespace s9e\TextFormatter\Configurator\TemplateNormalizations;
009
010 use DOMElement;
011
012 class OptimizeChoose extends AbstractChooseOptimization
013 {
014 /**
015 * Adopt the children of given element's only child
016 *
017 * @param DOMElement $branch
018 * @return void
019 */
020 protected function adoptChildren(DOMElement $branch)
021 {
022 while ($branch->firstChild->firstChild)
023 {
024 $branch->appendChild($branch->firstChild->removeChild($branch->firstChild->firstChild));
025 }
026 $branch->removeChild($branch->firstChild);
027 }
028
029 /**
030 * Test whether all branches of current xsl:choose element share a common firstChild/lastChild
031 *
032 * @param string $childType Either firstChild or lastChild
033 * @return bool
034 */
035 protected function matchBranches($childType)
036 {
037 $branches = $this->getBranches();
038 if (!isset($branches[0]->$childType))
039 {
040 return false;
041 }
042
043 $childNode = $branches[0]->$childType;
044 foreach ($branches as $branch)
045 {
046 if (!isset($branch->$childType) || !$this->isEqualNode($childNode, $branch->$childType))
047 {
048 return false;
049 }
050 }
051
052 return true;
053 }
054
055 /**
056 * Test whether all branches of current xsl:choose element have a single child with the same start tag
057 *
058 * @return bool
059 */
060 protected function matchOnlyChild()
061 {
062 $branches = $this->getBranches();
063 if (!isset($branches[0]->firstChild))
064 {
065 return false;
066 }
067
068 $firstChild = $branches[0]->firstChild;
069 if ($this->isXsl($firstChild, 'choose'))
070 {
071 // Abort on xsl:choose because we can't move it without moving its children
072 return false;
073 }
074
075 foreach ($branches as $branch)
076 {
077 if ($branch->childNodes->length !== 1 || !($branch->firstChild instanceof DOMElement))
078 {
079 return false;
080 }
081 if (!$this->isEqualTag($firstChild, $branch->firstChild))
082 {
083 return false;
084 }
085 }
086
087 return true;
088 }
089
090 /**
091 * Move the firstChild of each branch before current xsl:choose
092 *
093 * @return void
094 */
095 protected function moveFirstChildBefore()
096 {
097 $branches = $this->getBranches();
098 $this->choose->parentNode->insertBefore(array_pop($branches)->firstChild, $this->choose);
099 foreach ($branches as $branch)
100 {
101 $branch->removeChild($branch->firstChild);
102 }
103 }
104
105 /**
106 * Move the lastChild of each branch after current xsl:choose
107 *
108 * @return void
109 */
110 protected function moveLastChildAfter()
111 {
112 $branches = $this->getBranches();
113 $node = array_pop($branches)->lastChild;
114 if (isset($this->choose->nextSibling))
115 {
116 $this->choose->parentNode->insertBefore($node, $this->choose->nextSibling);
117 }
118 else
119 {
120 $this->choose->parentNode->appendChild($node);
121 }
122 foreach ($branches as $branch)
123 {
124 $branch->removeChild($branch->lastChild);
125 }
126 }
127
128 /**
129 * {@inheritdoc}
130 */
131 protected function optimizeChoose()
132 {
133 if ($this->hasOtherwise())
134 {
135 $this->optimizeCommonFirstChild();
136 $this->optimizeCommonLastChild();
137 $this->optimizeCommonOnlyChild();
138 $this->optimizeEmptyBranch();
139 $this->optimizeEmptyOtherwise();
140 }
141 if ($this->isEmpty())
142 {
143 $this->choose->parentNode->removeChild($this->choose);
144 }
145 else
146 {
147 $this->optimizeSingleBranch();
148 }
149 }
150
151 /**
152 * Optimize current xsl:choose by moving out the first child of each branch if they match
153 *
154 * @return void
155 */
156 protected function optimizeCommonFirstChild()
157 {
158 while ($this->matchBranches('firstChild'))
159 {
160 $this->moveFirstChildBefore();
161 }
162 }
163
164 /**
165 * Optimize current xsl:choose by moving out the last child of each branch if they match
166 *
167 * @return void
168 */
169 protected function optimizeCommonLastChild()
170 {
171 while ($this->matchBranches('lastChild'))
172 {
173 $this->moveLastChildAfter();
174 }
175 }
176
177 /**
178 * Optimize current xsl:choose by moving out only child of each branch if they match
179 *
180 * This will reorder xsl:choose/xsl:when/div into div/xsl:choose/xsl:when if every branch has
181 * the same only child (excluding the child's own descendants)
182 *
183 * @return void
184 */
185 protected function optimizeCommonOnlyChild()
186 {
187 while ($this->matchOnlyChild())
188 {
189 $this->reparentChild();
190 }
191 }
192
193 /**
194 * Switch the logic of an xsl:otherwise if the only other branch is empty
195 *
196 * @return void
197 */
198 protected function optimizeEmptyBranch()
199 {
200 $query = 'count(xsl:when) = 1 and count(xsl:when/node()) = 0 and xsl:otherwise';
201 if (!$this->xpath->evaluate($query, $this->choose))
202 {
203 return;
204 }
205
206 // test="@foo" becomes test="not(@foo)"
207 $when = $this->xpath('xsl:when', $this->choose)[0];
208 $when->setAttribute('test', 'not(' . $when->getAttribute('test') . ')');
209
210 $otherwise = $this->xpath('xsl:otherwise', $this->choose)[0];
211 while ($otherwise->firstChild)
212 {
213 $when->appendChild($otherwise->removeChild($otherwise->firstChild));
214 }
215 }
216
217 /**
218 * Optimize away the xsl:otherwise child of current xsl:choose if it's empty
219 *
220 * @return void
221 */
222 protected function optimizeEmptyOtherwise()
223 {
224 $query = 'xsl:otherwise[count(node()) = 0]';
225 foreach ($this->xpath($query, $this->choose) as $otherwise)
226 {
227 $this->choose->removeChild($otherwise);
228 }
229 }
230
231 /**
232 * Replace current xsl:choose with xsl:if if it has only one branch
233 *
234 * @return void
235 */
236 protected function optimizeSingleBranch()
237 {
238 $query = 'count(xsl:when) = 1 and not(xsl:otherwise)';
239 if (!$this->xpath->evaluate($query, $this->choose))
240 {
241 return;
242 }
243 $when = $this->xpath('xsl:when', $this->choose)[0];
244 $if = $this->createElement('xsl:if');
245 $if->setAttribute('test', $when->getAttribute('test'));
246 while ($when->firstChild)
247 {
248 $if->appendChild($when->removeChild($when->firstChild));
249 }
250
251 $this->choose->parentNode->replaceChild($if, $this->choose);
252 }
253
254 /**
255 * Reorder the current xsl:choose tree to make it a child of the first child of its first branch
256 *
257 * This will reorder xsl:choose/xsl:when/div into div/xsl:choose/xsl:when
258 *
259 * @return void
260 */
261 protected function reparentChild()
262 {
263 $branches = $this->getBranches();
264 $childNode = $branches[0]->firstChild->cloneNode();
265 $childNode->appendChild($this->choose->parentNode->replaceChild($childNode, $this->choose));
266
267 foreach ($branches as $branch)
268 {
269 $this->adoptChildren($branch);
270 }
271 }
272 }