PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.3.8
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.3.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.3.8, at vendor/symfony/css-selector/XPath/Translator.php

225 lines 7.1 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 $functionTranslators = [];
48 private array $pseudoClassTranslators = [];
49 private array $attributeMatchingTranslators = [];
50
51 public function __construct(?ParserInterface $parser = null)
52 {
53 $this->mainParser = $parser ?? new Parser();
54
55 $this
56 ->registerExtension(new Extension\NodeExtension())
57 ->registerExtension(new Extension\CombinationExtension())
58 ->registerExtension(new Extension\FunctionExtension())
59 ->registerExtension(new Extension\PseudoClassExtension())
60 ->registerExtension(new Extension\AttributeMatchingExtension())
61 ;
62 }
63
64 public static function getXpathLiteral(string $element): string
65 {
66 if (!str_contains($element, "'")) {
67 return "'".$element."'";
68 }
69
70 if (!str_contains($element, '"')) {
71 return '"'.$element.'"';
72 }
73
74 $string = $element;
75 $parts = [];
76 while (true) {
77 if (false !== $pos = strpos($string, "'")) {
78 $parts[] = \sprintf("'%s'", substr($string, 0, $pos));
79 $parts[] = "\"'\"";
80 $string = substr($string, $pos + 1);
81 } else {
82 $parts[] = "'$string'";
83 break;
84 }
85 }
86
87 return \sprintf('concat(%s)', implode(', ', $parts));
88 }
89
90 public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string
91 {
92 $selectors = $this->parseSelectors($cssExpr);
93
94 /** @var SelectorNode $selector */
95 foreach ($selectors as $index => $selector) {
96 if (null !== $selector->getPseudoElement()) {
97 throw new ExpressionErrorException('Pseudo-elements are not supported.');
98 }
99
100 $selectors[$index] = $this->selectorToXPath($selector, $prefix);
101 }
102
103 return implode(' | ', $selectors);
104 }
105
106 public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string
107 {
108 return ($prefix ?: '').$this->nodeToXPath($selector);
109 }
110
111 /**
112 * @return $this
113 */
114 public function registerExtension(Extension\ExtensionInterface $extension): static
115 {
116 $this->extensions[$extension->getName()] = $extension;
117
118 $this->nodeTranslators = array_merge($this->nodeTranslators, $extension->getNodeTranslators());
119 $this->combinationTranslators = array_merge($this->combinationTranslators, $extension->getCombinationTranslators());
120 $this->functionTranslators = array_merge($this->functionTranslators, $extension->getFunctionTranslators());
121 $this->pseudoClassTranslators = array_merge($this->pseudoClassTranslators, $extension->getPseudoClassTranslators());
122 $this->attributeMatchingTranslators = array_merge($this->attributeMatchingTranslators, $extension->getAttributeMatchingTranslators());
123
124 return $this;
125 }
126
127 /**
128 * @throws ExpressionErrorException
129 */
130 public function getExtension(string $name): Extension\ExtensionInterface
131 {
132 if (!isset($this->extensions[$name])) {
133 throw new ExpressionErrorException(\sprintf('Extension "%s" not registered.', $name));
134 }
135
136 return $this->extensions[$name];
137 }
138
139 /**
140 * @return $this
141 */
142 public function registerParserShortcut(ParserInterface $shortcut): static
143 {
144 $this->shortcutParsers[] = $shortcut;
145
146 return $this;
147 }
148
149 /**
150 * @throws ExpressionErrorException
151 */
152 public function nodeToXPath(NodeInterface $node): XPathExpr
153 {
154 if (!isset($this->nodeTranslators[$node->getNodeName()])) {
155 throw new ExpressionErrorException(\sprintf('Node "%s" not supported.', $node->getNodeName()));
156 }
157
158 return $this->nodeTranslators[$node->getNodeName()]($node, $this);
159 }
160
161 /**
162 * @throws ExpressionErrorException
163 */
164 public function addCombination(string $combiner, NodeInterface $xpath, NodeInterface $combinedXpath): XPathExpr
165 {
166 if (!isset($this->combinationTranslators[$combiner])) {
167 throw new ExpressionErrorException(\sprintf('Combiner "%s" not supported.', $combiner));
168 }
169
170 return $this->combinationTranslators[$combiner]($this->nodeToXPath($xpath), $this->nodeToXPath($combinedXpath));
171 }
172
173 /**
174 * @throws ExpressionErrorException
175 */
176 public function addFunction(XPathExpr $xpath, FunctionNode $function): XPathExpr
177 {
178 if (!isset($this->functionTranslators[$function->getName()])) {
179 throw new ExpressionErrorException(\sprintf('Function "%s" not supported.', $function->getName()));
180 }
181
182 return $this->functionTranslators[$function->getName()]($xpath, $function);
183 }
184
185 /**
186 * @throws ExpressionErrorException
187 */
188 public function addPseudoClass(XPathExpr $xpath, string $pseudoClass): XPathExpr
189 {
190 if (!isset($this->pseudoClassTranslators[$pseudoClass])) {
191 throw new ExpressionErrorException(\sprintf('Pseudo-class "%s" not supported.', $pseudoClass));
192 }
193
194 return $this->pseudoClassTranslators[$pseudoClass]($xpath);
195 }
196
197 /**
198 * @throws ExpressionErrorException
199 */
200 public function addAttributeMatching(XPathExpr $xpath, string $operator, string $attribute, ?string $value): XPathExpr
201 {
202 if (!isset($this->attributeMatchingTranslators[$operator])) {
203 throw new ExpressionErrorException(\sprintf('Attribute matcher operator "%s" not supported.', $operator));
204 }
205
206 return $this->attributeMatchingTranslators[$operator]($xpath, $attribute, $value);
207 }
208
209 /**
210 * @return SelectorNode[]
211 */
212 private function parseSelectors(string $css): array
213 {
214 foreach ($this->shortcutParsers as $shortcut) {
215 $tokens = $shortcut->parse($css);
216
217 if ($tokens) {
218 return $tokens;
219 }
220 }
221
222 return $this->mainParser->parse($css);
223 }
224 }
225