PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.8
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.8
4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 All 139 releases
learnpress / vendor / symfony / css-selector / XPath / Extension / NodeExtension.php

NodeExtension.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.8, at vendor/symfony/css-selector/XPath/Extension/NodeExtension.php

247 lines 7.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Symfony\Component\CssSelector\XPath\Extension;
13
14 use Symfony\Component\CssSelector\Node;
15 use Symfony\Component\CssSelector\XPath\Translator;
16 use Symfony\Component\CssSelector\XPath\XPathExpr;
17
18 /**
19 * XPath expression translator node extension.
20 *
21 * This component is a port of the Python cssselect library,
22 * which is copyright Ian Bicking, @see https://github.com/scrapy/cssselect.
23 *
24 * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
25 *
26 * @internal
27 */
28 class NodeExtension extends AbstractExtension
29 {
30 public const ELEMENT_NAME_IN_LOWER_CASE = 1;
31 public const ATTRIBUTE_NAME_IN_LOWER_CASE = 2;
32 public const ATTRIBUTE_VALUE_IN_LOWER_CASE = 4;
33
34 public function __construct(
35 private int $flags = 0,
36 ) {
37 }
38
39 /**
40 * @return $this
41 */
42 public function setFlag(int $flag, bool $on): static
43 {
44 if ($on && !$this->hasFlag($flag)) {
45 $this->flags += $flag;
46 }
47
48 if (!$on && $this->hasFlag($flag)) {
49 $this->flags -= $flag;
50 }
51
52 return $this;
53 }
54
55 public function hasFlag(int $flag): bool
56 {
57 return (bool) ($this->flags & $flag);
58 }
59
60 public function getNodeTranslators(): array
61 {
62 return [
63 'Selector' => $this->translateSelector(...),
64 'CombinedSelector' => $this->translateCombinedSelector(...),
65 'Negation' => $this->translateNegation(...),
66 'Matching' => $this->translateMatching(...),
67 'SpecificityAdjustment' => $this->translateSpecificityAdjustment(...),
68 'Function' => $this->translateFunction(...),
69 'Pseudo' => $this->translatePseudo(...),
70 'Attribute' => $this->translateAttribute(...),
71 'Class' => $this->translateClass(...),
72 'Hash' => $this->translateHash(...),
73 'Element' => $this->translateElement(...),
74 'Relation' => $this->translateRelation(...),
75 ];
76 }
77
78 public function translateSelector(Node\SelectorNode $node, Translator $translator): XPathExpr
79 {
80 return $translator->nodeToXPath($node->getTree());
81 }
82
83 public function translateCombinedSelector(Node\CombinedSelectorNode $node, Translator $translator): XPathExpr
84 {
85 return $translator->addCombination($node->getCombinator(), $node->getSelector(), $node->getSubSelector());
86 }
87
88 public function translateNegation(Node\NegationNode $node, Translator $translator): XPathExpr
89 {
90 $xpath = $translator->nodeToXPath($node->getSelector());
91 $subXpath = $translator->nodeToXPath($node->getSubSelector());
92 $subXpath->addNameTest();
93
94 if ($subXpath->getCondition()) {
95 return $xpath->addCondition(\sprintf('not(%s)', $subXpath->getCondition()));
96 }
97
98 return $xpath->addCondition('0');
99 }
100
101 public function translateMatching(Node\MatchingNode $node, Translator $translator): XPathExpr
102 {
103 return $this->translateMatchingOrSpecificityAdjustment($node->selector, $node->arguments, $translator);
104 }
105
106 public function translateSpecificityAdjustment(Node\SpecificityAdjustmentNode $node, Translator $translator): XPathExpr
107 {
108 return $this->translateMatchingOrSpecificityAdjustment($node->selector, $node->arguments, $translator);
109 }
110
111 /**
112 * @param array<Node\NodeInterface> $arguments
113 */
114 private function translateMatchingOrSpecificityAdjustment(Node\NodeInterface $selector, array $arguments, Translator $translator): XPathExpr
115 {
116 $xpath = $translator->nodeToXPath($selector);
117
118 $conditions = [];
119 foreach ($arguments as $argument) {
120 $expr = $translator->nodeToXPath($argument);
121 $expr->addNameTest();
122 if ('' !== $condition = $expr->getCondition()) {
123 $conditions[] = $condition;
124 }
125 }
126
127 if ($conditions) {
128 $xpath->addCondition(1 === \count($conditions) ? $conditions[0] : '('.implode(') or (', $conditions).')');
129 }
130
131 return $xpath;
132 }
133
134 public function translateFunction(Node\FunctionNode $node, Translator $translator): XPathExpr
135 {
136 $xpath = $translator->nodeToXPath($node->getSelector());
137
138 return $translator->addFunction($xpath, $node);
139 }
140
141 public function translatePseudo(Node\PseudoNode $node, Translator $translator): XPathExpr
142 {
143 $xpath = $translator->nodeToXPath($node->getSelector());
144
145 return $translator->addPseudoClass($xpath, $node->getIdentifier());
146 }
147
148 public function translateAttribute(Node\AttributeNode $node, Translator $translator): XPathExpr
149 {
150 $name = $node->getAttribute();
151 $safe = $this->isSafeName($name);
152
153 if ($this->hasFlag(self::ATTRIBUTE_NAME_IN_LOWER_CASE)) {
154 $name = strtolower($name);
155 }
156
157 if ($node->getNamespace()) {
158 $name = \sprintf('%s:%s', $node->getNamespace(), $name);
159 $safe = $safe && $this->isSafeName($node->getNamespace());
160 }
161
162 $attribute = $safe ? '@'.$name : \sprintf('attribute::*[name() = %s]', Translator::getXpathLiteral($name));
163 $value = $node->getValue();
164 $xpath = $translator->nodeToXPath($node->getSelector());
165
166 if ($this->hasFlag(self::ATTRIBUTE_VALUE_IN_LOWER_CASE)) {
167 $value = strtolower($value);
168 }
169
170 return $translator->addAttributeMatching($xpath, $node->getOperator(), $attribute, $value);
171 }
172
173 public function translateClass(Node\ClassNode $node, Translator $translator): XPathExpr
174 {
175 $xpath = $translator->nodeToXPath($node->getSelector());
176
177 return $translator->addAttributeMatching($xpath, '~=', '@class', $node->getName());
178 }
179
180 public function translateHash(Node\HashNode $node, Translator $translator): XPathExpr
181 {
182 $xpath = $translator->nodeToXPath($node->getSelector());
183
184 return $translator->addAttributeMatching($xpath, '=', '@id', $node->getId());
185 }
186
187 public function translateElement(Node\ElementNode $node): XPathExpr
188 {
189 $element = $node->getElement();
190
191 if ($element && $this->hasFlag(self::ELEMENT_NAME_IN_LOWER_CASE)) {
192 $element = strtolower($element);
193 }
194
195 if ($element) {
196 $safe = $this->isSafeName($element);
197 } else {
198 $element = '*';
199 $safe = true;
200 }
201
202 if ($node->getNamespace()) {
203 $element = \sprintf('%s:%s', $node->getNamespace(), $element);
204 $safe = $safe && $this->isSafeName($node->getNamespace());
205 }
206
207 $xpath = new XPathExpr('', $element);
208
209 if (!$safe) {
210 $xpath->addNameTest();
211 }
212
213 return $xpath;
214 }
215
216 public function translateRelation(Node\RelationNode $node, Translator $translator): XPathExpr
217 {
218 $arguments = $node->getArguments();
219 if (1 === \count($arguments)) {
220 [$combinator, $subSelector] = $arguments[0];
221
222 return $translator->addRelativeCombination($combinator, $node->getSelector(), $subSelector);
223 }
224
225 $conditions = [];
226 foreach ($arguments as [$combinator, $subSelector]) {
227 $relativeXpath = (string) $translator->addRelativeCombination($combinator, new Node\ElementNode(), $subSelector);
228 $conditions[] = substr($relativeXpath, 2, -1);
229 }
230
231 $xpath = $translator->nodeToXPath($node->getSelector());
232 $xpath->addCondition('('.implode(') or (', $conditions).')');
233
234 return $xpath;
235 }
236
237 public function getName(): string
238 {
239 return 'node';
240 }
241
242 private function isSafeName(string $name): bool
243 {
244 return 0 < preg_match('~^[a-zA-Z_][a-zA-Z0-9_.-]*$~', $name);
245 }
246 }
247