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 / Translator.php

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

239 lines 7.9 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;
13
14 use Symfony\Component\CssSelector\Exception\ExpressionErrorException;
15 use Symfony\Component\CssSelector\Node\FunctionNode;
16 use Symfony\Component\CssSelector\Node\NodeInterface;
17 use Symfony\Component\CssSelector\Node\SelectorNode;
18 use Symfony\Component\CssSelector\Parser\Parser;
19 use Symfony\Component\CssSelector\Parser\ParserInterface;
20
21 /**
22 * XPath expression translator interface.
23 *
24 * This component is a port of the Python cssselect library,
25 * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
26 *
27 * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
28 *
29 * @internal
30 */
31 class Translator implements TranslatorInterface
32 {
33 private ParserInterface $mainParser;
34
35 /**
36 * @var ParserInterface[]
37 */
38 private array $shortcutParsers = [];
39
40 /**
41 * @var Extension\ExtensionInterface[]
42 */
43 private array $extensions = [];
44
45 private array $nodeTranslators = [];
46 private array $combinationTranslators = [];
47 private array $relativeCombinationTranslators = [];
48 private array $functionTranslators = [];
49 private array $pseudoClassTranslators = [];
50 private array $attributeMatchingTranslators = [];
51
52 public function __construct(?ParserInterface $parser = null)
53 {
54 $this->mainParser = $parser ?? new Parser();
55
56 $this
57 ->registerExtension(new Extension\NodeExtension())
58 ->registerExtension(new Extension\CombinationExtension())
59 ->registerExtension(new Extension\FunctionExtension())
60 ->registerExtension(new Extension\PseudoClassExtension())
61 ->registerExtension(new Extension\AttributeMatchingExtension())
62 ->registerExtension(new Extension\RelationExtension())
63 ;
64 }
65
66 public static function getXpathLiteral(string $element): string
67 {
68 if (!str_contains($element, "'")) {
69 return "'".$element."'";
70 }
71
72 if (!str_contains($element, '"')) {
73 return '"'.$element.'"';
74 }
75
76 $string = $element;
77 $parts = [];
78 while (true) {
79 if (false !== $pos = strpos($string, "'")) {
80 $parts[] = \sprintf("'%s'", substr($string, 0, $pos));
81 $parts[] = "\"'\"";
82 $string = substr($string, $pos + 1);
83 } else {
84 $parts[] = "'$string'";
85 break;
86 }
87 }
88
89 return \sprintf('concat(%s)', implode(', ', $parts));
90 }
91
92 public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string
93 {
94 $selectors = $this->parseSelectors($cssExpr);
95
96 foreach ($selectors as $index => $selector) {
97 if (null !== $selector->getPseudoElement()) {
98 throw new ExpressionErrorException('Pseudo-elements are not supported.');
99 }
100
101 $selectors[$index] = $this->selectorToXPath($selector, $prefix);
102 }
103
104 return implode(' | ', $selectors);
105 }
106
107 public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string
108 {
109 return ($prefix ?: '').$this->nodeToXPath($selector);
110 }
111
112 /**
113 * @return $this
114 */
115 public function registerExtension(Extension\ExtensionInterface $extension): static
116 {
117 $this->extensions[$extension->getName()] = $extension;
118
119 $this->nodeTranslators = array_merge($this->nodeTranslators, $extension->getNodeTranslators());
120 $this->combinationTranslators = array_merge($this->combinationTranslators, $extension->getCombinationTranslators());
121 $this->functionTranslators = array_merge($this->functionTranslators, $extension->getFunctionTranslators());
122 $this->pseudoClassTranslators = array_merge($this->pseudoClassTranslators, $extension->getPseudoClassTranslators());
123 $this->attributeMatchingTranslators = array_merge($this->attributeMatchingTranslators, $extension->getAttributeMatchingTranslators());
124 $this->relativeCombinationTranslators = array_merge($this->relativeCombinationTranslators, $extension->getRelativeCombinationTranslators());
125
126 return $this;
127 }
128
129 /**
130 * @throws ExpressionErrorException
131 */
132 public function getExtension(string $name): Extension\ExtensionInterface
133 {
134 if (!isset($this->extensions[$name])) {
135 throw new ExpressionErrorException(\sprintf('Extension "%s" not registered.', $name));
136 }
137
138 return $this->extensions[$name];
139 }
140
141 /**
142 * @return $this
143 */
144 public function registerParserShortcut(ParserInterface $shortcut): static
145 {
146 $this->shortcutParsers[] = $shortcut;
147
148 return $this;
149 }
150
151 /**
152 * @throws ExpressionErrorException
153 */
154 public function nodeToXPath(NodeInterface $node): XPathExpr
155 {
156 if (!isset($this->nodeTranslators[$node->getNodeName()])) {
157 throw new ExpressionErrorException(\sprintf('Node "%s" not supported.', $node->getNodeName()));
158 }
159
160 return $this->nodeTranslators[$node->getNodeName()]($node, $this);
161 }
162
163 /**
164 * @throws ExpressionErrorException
165 */
166 public function addCombination(string $combiner, NodeInterface $xpath, NodeInterface $combinedXpath): XPathExpr
167 {
168 if (!isset($this->combinationTranslators[$combiner])) {
169 throw new ExpressionErrorException(\sprintf('Combiner "%s" not supported.', $combiner));
170 }
171
172 return $this->combinationTranslators[$combiner]($this->nodeToXPath($xpath), $this->nodeToXPath($combinedXpath));
173 }
174
175 /**
176 * @throws ExpressionErrorException
177 */
178 public function addRelativeCombination(string $combiner, NodeInterface $xpath, NodeInterface $combinedXpath): XPathExpr
179 {
180 if (!isset($this->relativeCombinationTranslators[$combiner])) {
181 throw new ExpressionErrorException(\sprintf('Combiner "%s" not supported.', $combiner));
182 }
183
184 return $this->relativeCombinationTranslators[$combiner]($this->nodeToXPath($xpath), $this->nodeToXPath($combinedXpath));
185 }
186
187 /**
188 * @throws ExpressionErrorException
189 */
190 public function addFunction(XPathExpr $xpath, FunctionNode $function): XPathExpr
191 {
192 if (!isset($this->functionTranslators[$function->getName()])) {
193 throw new ExpressionErrorException(\sprintf('Function "%s" not supported.', $function->getName()));
194 }
195
196 return $this->functionTranslators[$function->getName()]($xpath, $function);
197 }
198
199 /**
200 * @throws ExpressionErrorException
201 */
202 public function addPseudoClass(XPathExpr $xpath, string $pseudoClass): XPathExpr
203 {
204 if (!isset($this->pseudoClassTranslators[$pseudoClass])) {
205 throw new ExpressionErrorException(\sprintf('Pseudo-class "%s" not supported.', $pseudoClass));
206 }
207
208 return $this->pseudoClassTranslators[$pseudoClass]($xpath);
209 }
210
211 /**
212 * @throws ExpressionErrorException
213 */
214 public function addAttributeMatching(XPathExpr $xpath, string $operator, string $attribute, ?string $value): XPathExpr
215 {
216 if (!isset($this->attributeMatchingTranslators[$operator])) {
217 throw new ExpressionErrorException(\sprintf('Attribute matcher operator "%s" not supported.', $operator));
218 }
219
220 return $this->attributeMatchingTranslators[$operator]($xpath, $attribute, $value);
221 }
222
223 /**
224 * @return SelectorNode[]
225 */
226 private function parseSelectors(string $css): array
227 {
228 foreach ($this->shortcutParsers as $shortcut) {
229 $tokens = $shortcut->parse($css);
230
231 if ($tokens) {
232 return $tokens;
233 }
234 }
235
236 return $this->mainParser->parse($css);
237 }
238 }
239