PluginProbe ʕ •ᴥ•ʔ
WP Job Manager / 2.4.7
WP Job Manager v2.4.7
2.4.7 2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.1.0 1.1.1 1.1.2 1.1.3 1.10.0 1.11.0 1.11.1 1.12.0 1.12.1 1.13.0 1.14.0 1.15.0 1.16.0 1.16.1 1.17.0 1.18.0 1.19.0 1.2.0 1.20.0 1.20.1 1.21.0 1.21.1 1.21.2 1.21.3 1.21.4 1.22.0 1.22.1 1.22.2 1.22.3 1.23.0 1.23.1 1.23.10 1.23.11 1.23.12 1.23.13 1.23.2 1.23.3 1.23.4 1.23.5 1.23.6 1.23.7 1.23.8 1.23.9 1.24.0 1.24.0.1 1.25.0 1.25.0.1 1.25.1 1.25.1.1 1.25.2 1.25.2.1 1.25.3 1.25.3.1 1.26.0 1.26.0.1 1.26.1 1.26.1.1 1.26.2 1.26.2.1 1.27.0 1.27.0.1 1.28.0 1.28.0.1 1.29.0 1.29.0.1 1.29.1 1.29.1.1 1.29.2 1.29.2.1 1.29.3 1.29.3.1 1.3.0 1.3.1 1.30.0 1.30.0.1 1.30.1 1.30.1.1 1.30.2 1.30.2.1 1.31.0 1.31.0.1 1.31.1 1.31.1.1 1.31.2 1.31.3 1.32.0 1.32.1 1.32.2 1.32.3 1.33.0 1.33.1 1.33.2 1.33.3 1.33.4 1.33.5 1.34.0 1.34.1 1.34.2 1.34.3 1.34.4 1.34.5 1.35.0 1.35.1 1.35.2 1.35.3 1.36.0 1.36.1 1.36.2 1.37.0 1.38.0 1.38.1 1.39.0 1.4.0 1.40.0 1.40.1 1.40.2 1.41.0 1.42.0 1.5.0 1.5.1 1.5.2 1.6.0 1.7.0 1.7.1 1.7.3 1.8.0 1.8.1 1.8.2 1.9.0 1.9.1 1.9.2 1.9.3 2.0.0 2.1.0 2.1.1 2.2.0 2.2.1 2.2.2 2.3.0 2.4.0 2.4.1
wp-job-manager / vendor / symfony / css-selector / XPath / Translator.php
wp-job-manager / vendor / symfony / css-selector / XPath Last commit date
Extension 2 years ago Translator.php 2 years ago TranslatorInterface.php 2 years ago XPathExpr.php 2 years ago
Translator.php
231 lines
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 $mainParser;
34
35 /**
36 * @var ParserInterface[]
37 */
38 private $shortcutParsers = [];
39
40 /**
41 * @var Extension\ExtensionInterface[]
42 */
43 private $extensions = [];
44
45 private $nodeTranslators = [];
46 private $combinationTranslators = [];
47 private $functionTranslators = [];
48 private $pseudoClassTranslators = [];
49 private $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 /**
91 * {@inheritdoc}
92 */
93 public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string
94 {
95 $selectors = $this->parseSelectors($cssExpr);
96
97 /** @var SelectorNode $selector */
98 foreach ($selectors as $index => $selector) {
99 if (null !== $selector->getPseudoElement()) {
100 throw new ExpressionErrorException('Pseudo-elements are not supported.');
101 }
102
103 $selectors[$index] = $this->selectorToXPath($selector, $prefix);
104 }
105
106 return implode(' | ', $selectors);
107 }
108
109 /**
110 * {@inheritdoc}
111 */
112 public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string
113 {
114 return ($prefix ?: '').$this->nodeToXPath($selector);
115 }
116
117 /**
118 * @return $this
119 */
120 public function registerExtension(Extension\ExtensionInterface $extension): self
121 {
122 $this->extensions[$extension->getName()] = $extension;
123
124 $this->nodeTranslators = array_merge($this->nodeTranslators, $extension->getNodeTranslators());
125 $this->combinationTranslators = array_merge($this->combinationTranslators, $extension->getCombinationTranslators());
126 $this->functionTranslators = array_merge($this->functionTranslators, $extension->getFunctionTranslators());
127 $this->pseudoClassTranslators = array_merge($this->pseudoClassTranslators, $extension->getPseudoClassTranslators());
128 $this->attributeMatchingTranslators = array_merge($this->attributeMatchingTranslators, $extension->getAttributeMatchingTranslators());
129
130 return $this;
131 }
132
133 /**
134 * @throws ExpressionErrorException
135 */
136 public function getExtension(string $name): Extension\ExtensionInterface
137 {
138 if (!isset($this->extensions[$name])) {
139 throw new ExpressionErrorException(sprintf('Extension "%s" not registered.', $name));
140 }
141
142 return $this->extensions[$name];
143 }
144
145 /**
146 * @return $this
147 */
148 public function registerParserShortcut(ParserInterface $shortcut): self
149 {
150 $this->shortcutParsers[] = $shortcut;
151
152 return $this;
153 }
154
155 /**
156 * @throws ExpressionErrorException
157 */
158 public function nodeToXPath(NodeInterface $node): XPathExpr
159 {
160 if (!isset($this->nodeTranslators[$node->getNodeName()])) {
161 throw new ExpressionErrorException(sprintf('Node "%s" not supported.', $node->getNodeName()));
162 }
163
164 return $this->nodeTranslators[$node->getNodeName()]($node, $this);
165 }
166
167 /**
168 * @throws ExpressionErrorException
169 */
170 public function addCombination(string $combiner, NodeInterface $xpath, NodeInterface $combinedXpath): XPathExpr
171 {
172 if (!isset($this->combinationTranslators[$combiner])) {
173 throw new ExpressionErrorException(sprintf('Combiner "%s" not supported.', $combiner));
174 }
175
176 return $this->combinationTranslators[$combiner]($this->nodeToXPath($xpath), $this->nodeToXPath($combinedXpath));
177 }
178
179 /**
180 * @throws ExpressionErrorException
181 */
182 public function addFunction(XPathExpr $xpath, FunctionNode $function): XPathExpr
183 {
184 if (!isset($this->functionTranslators[$function->getName()])) {
185 throw new ExpressionErrorException(sprintf('Function "%s" not supported.', $function->getName()));
186 }
187
188 return $this->functionTranslators[$function->getName()]($xpath, $function);
189 }
190
191 /**
192 * @throws ExpressionErrorException
193 */
194 public function addPseudoClass(XPathExpr $xpath, string $pseudoClass): XPathExpr
195 {
196 if (!isset($this->pseudoClassTranslators[$pseudoClass])) {
197 throw new ExpressionErrorException(sprintf('Pseudo-class "%s" not supported.', $pseudoClass));
198 }
199
200 return $this->pseudoClassTranslators[$pseudoClass]($xpath);
201 }
202
203 /**
204 * @throws ExpressionErrorException
205 */
206 public function addAttributeMatching(XPathExpr $xpath, string $operator, string $attribute, ?string $value): XPathExpr
207 {
208 if (!isset($this->attributeMatchingTranslators[$operator])) {
209 throw new ExpressionErrorException(sprintf('Attribute matcher operator "%s" not supported.', $operator));
210 }
211
212 return $this->attributeMatchingTranslators[$operator]($xpath, $attribute, $value);
213 }
214
215 /**
216 * @return SelectorNode[]
217 */
218 private function parseSelectors(string $css): array
219 {
220 foreach ($this->shortcutParsers as $shortcut) {
221 $tokens = $shortcut->parse($css);
222
223 if (!empty($tokens)) {
224 return $tokens;
225 }
226 }
227
228 return $this->mainParser->parse($css);
229 }
230 }
231