PluginProbe ʕ •ᴥ•ʔ
WP All Import – Drag & Drop Import for CSV, XML, Excel & Google Sheets / 2.13
WP All Import – Drag & Drop Import for CSV, XML, Excel & Google Sheets v2.13
4.1.1 3.9.5 3.9.6 4.0.0 4.0.1 4.1.0 trunk 2.12 2.13 2.14 3.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.6 3.4.7 3.4.8 3.4.9 3.5.0 3.5.1 3.5.2 3.5.3 3.5.4 3.5.5 3.5.6 3.5.7 3.5.8 3.5.9 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.6.9 3.7.0 3.7.1 3.7.2 3.7.3 3.7.3-beta-1.0 3.7.4 3.7.4-beta-1.0 3.7.5 3.7.6 3.7.7 3.7.8 3.7.9 3.8.0 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4
wp-all-import / libraries / XmlImportTemplateParser.php
wp-all-import / libraries Last commit date
ast 14 years ago cache 14 years ago XmlImportConfig.php 14 years ago XmlImportCsvParse.php 14 years ago XmlImportException.php 14 years ago XmlImportParser.php 14 years ago XmlImportReaderInterface.php 14 years ago XmlImportStringReader.php 14 years ago XmlImportTemplate.php 14 years ago XmlImportTemplateCodeGenerator.php 14 years ago XmlImportTemplateParser.php 14 years ago XmlImportTemplateScanner.php 14 years ago XmlImportToken.php 14 years ago
XmlImportTemplateParser.php
393 lines
1 <?php
2 /**
3 * @author Olexandr Zanichkovsky <olexandr.zanichkovsky@zophiatech.com>
4 * @package General
5 */
6
7 require_once dirname(__FILE__) . '/ast/XmlImportAstSequence.php';
8 require_once dirname(__FILE__) . '/ast/XmlImportAstPrint.php';
9 require_once dirname(__FILE__) . '/ast/XmlImportAstText.php';
10 require_once dirname(__FILE__) . '/ast/XmlImportAstWith.php';
11 require_once dirname(__FILE__) . '/ast/XmlImportAstForeach.php';
12 require_once dirname(__FILE__) . '/ast/XmlImportAstIf.php';
13 require_once dirname(__FILE__) . '/ast/XmlImportAstMath.php';
14
15 require_once dirname(__FILE__) . '/ast/XmlImportAstXPath.php';
16 require_once dirname(__FILE__) . '/ast/XmlImportAstString.php';
17 require_once dirname(__FILE__) . '/ast/XmlImportAstInteger.php';
18 require_once dirname(__FILE__) . '/ast/XmlImportAstFloat.php';
19 require_once dirname(__FILE__) . '/ast/XmlImportAstFunction.php';
20
21 /**
22 * Parses a list of nodes into AST (Abstract Syntax Tree)
23 */
24 class XmlImportTemplateParser
25 {
26 /**
27 * List of tokens
28 *
29 * @var array
30 */
31 private $tokens;
32
33 /**
34 * Current index
35 *
36 * @var int
37 */
38 private $index = -1;
39
40 /**
41 * Stack that stores possible block endings
42 *
43 * @var array
44 */
45 private $clauseStack = array();
46
47 /**
48 * Stack of sequences
49 *
50 * @var array
51 */
52 private $sequenceStack = array();
53
54 /**
55 * Whether else subclause is allowed
56 *
57 * @var bool
58 */
59 private $elseAllowed = false;
60
61 /**
62 * Creates new instance
63 *
64 * @param array $tokens
65 */
66 public function __construct(array $tokens)
67 {
68 $this->tokens = $tokens;
69 }
70
71 /**
72 * Parses the list of tokens into AST tree
73 *
74 * @return XmlImportAstSequence
75 */
76 public function parse()
77 {
78 $result = $this->parseSequence();
79
80 if (count($this->clauseStack) > 0)
81 throw new XmlImportException("Unexpected end of template.");
82
83 return $result;
84 }
85
86 /**
87 * Parses sequence
88 *
89 * @return XmlImportAstSequence
90 */
91 private function parseSequence()
92 {
93 if (($this->index + 1) == count($this->tokens))
94 throw new XmlImportException("Reached end of template but statement sequence expected");
95 $sequence = new XmlImportAstSequence();
96 array_push($this->sequenceStack, $sequence);
97 if (count($this->clauseStack) == 0)
98 {
99 while (($this->index + 1) < count($this->tokens))
100 {
101 $sequence->addStatement($this->parseStatement());
102 }
103 }
104 else
105 {
106 while (($this->index + 1) < count($this->tokens))
107 {
108 if ($this->tokens[$this->index + 1]->getKind() == $this->clauseStack[count($this->clauseStack) - 1])
109 {
110 $this->index++;
111 array_pop($this->clauseStack);
112 break;
113 }
114 $statement = $this->parseStatement();
115 if (is_null($statement))
116 return $sequence;
117 $sequence->addStatement($statement);
118 }
119 }
120 array_pop($this->sequenceStack);
121
122 return $sequence;
123 }
124
125 /**
126 * Parses statement
127 *
128 * @return XmlImportAstText
129 */
130 private function parseStatement()
131 {
132 if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_TEXT)
133 {
134 return new XmlImportAstText($this->tokens[++$this->index]->getValue());
135 }
136 elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_PRINT)
137 {
138 $this->index++;
139 return new XmlImportAstPrint($this->parseExpression());
140 }
141 elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_WITH)
142 {
143 return $this->parseWith();
144 }
145 elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_FOREACH)
146 {
147 return $this->parseForeach();
148 }
149 elseif($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_MATH)
150 {
151 return new XmlImportAstPrint($this->parseExpression());
152 }
153 elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_IF)
154 {
155 return $this->parseIf();
156 }
157 elseif($this->clauseStack[count($this->clauseStack) - 1] == XmlImportToken::KIND_ENDIF &&
158 in_array($this->tokens[$this->index + 1]->getKind(), array(XmlImportToken::KIND_ELSE, XmlImportToken::KIND_ELSEIF)))
159 {
160 if ($this->elseAllowed)
161 {
162 if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_ELSE)
163 $this->elseAllowed = false;
164 }
165 else
166 {
167 throw new XmlImportException("ELSEIF or ELSE is not allowed again after ELSE");
168 }
169 return null;
170 }
171 else
172 throw new XmlImportException ("Unexpected token {$this->tokens[$this->index + 1]->getKind()}, statement was expected.");
173 }
174
175 /**
176 * Parses expression
177 *
178 * @return XmlImportAstXPath
179 */
180 private function parseExpression()
181 {
182 if ($this->index + 1 == count($this->tokens))
183 throw new XmlImportException("Reached end of template but expression was expected");
184 if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_FUNCTION)
185 {
186 return $this->parseFunction();
187 }
188 elseif($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_MATH)
189 {
190 return $this->parseMath();
191 }
192 elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_XPATH)
193 {
194 $xpath = new XmlImportAstXPath($this->tokens[++$this->index]->getValue());
195 $this->sequenceStack[count($this->sequenceStack) - 1]->addVariable($xpath);
196 return $xpath;
197 }
198 elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_STRING || $this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_OPERATION)
199 {
200 return new XmlImportAstString($this->tokens[++$this->index]->getValue());
201 }
202 elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_INT)
203 {
204 return new XmlImportAstInteger($this->tokens[++$this->index]->getValue());
205 }
206 elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_FLOAT)
207 {
208 return new XmlImportAstFloat($this->tokens[++$this->index]->getValue());
209 }
210 else
211 throw new XmlImportException("Unexpected token " . $this->tokens[$this->index + 1]->getKind());
212 }
213
214 /**
215 * Parses function
216 *
217 * @return XmlImportAstFunction
218 */
219 private function parseFunction()
220 {
221 $function = new XmlImportAstFunction($this->tokens[++$this->index]->getValue());
222 if ($this->tokens[$this->index + 1]->getKind() != XmlImportToken::KIND_OPEN)
223 throw new XmlImportException ("Open brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
224 $this->index++;
225 if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
226 {
227 $this->index++;
228 return $function;
229 }
230 else
231 {
232 while ($this->index < count($this->tokens) - 2)
233 {
234 $function->addArgument($this->parseExpression());
235 if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
236 {
237 $this->index++;
238 return $function;
239 break;
240 }
241 elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_COMMA)
242 $this->index++;
243 else
244 throw new XmlImportException("Comma or closing brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
245 }
246 throw new XmlImportException("Unexpected end of {$function->getName()} function argument list");
247 }
248 }
249
250 /**
251 * Parses function
252 *
253 * @return XmlImportAstFunction
254 */
255 private function parseMath()
256 {
257 $math = new XmlImportAstMath($this->tokens[++$this->index]->getValue());
258 if ($this->tokens[$this->index + 1]->getKind() != XmlImportToken::KIND_OPEN)
259 throw new XmlImportException ("Open brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
260 $this->index++;
261 if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
262 {
263 $this->index++;
264 return $math;
265 }
266 else
267 {
268 while ($this->index < count($this->tokens) - 2)
269 {
270 $math->addArgument($this->parseExpression());
271 if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
272 {
273 $this->index++;
274 return $math;
275 break;
276 }
277 elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_COMMA)
278 $this->index++;
279 else
280 throw new XmlImportException("Comma or closing brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
281 }
282 throw new XmlImportException("Unexpected end of MATH argument list");
283 }
284 }
285
286 /**
287 * Parses clause that uses XPath and returns XPath
288 *
289 * @return XmlImportAstXPath
290 */
291 private function parseXPathDependant()
292 {
293 $this->index++;
294
295 if ($this->index + 1 == count($this->tokens))
296 throw new XmlImportException("Reached end of template but expression was expected");
297
298 if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_OPEN)
299 $this->index++;
300 else
301 throw new XmlImportException("Open brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
302 if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_XPATH)
303 {
304 $xpath = new XmlImportAstXPath($this->tokens[++$this->index]->getValue());
305 $this->sequenceStack[count($this->sequenceStack) - 1]->addVariable($xpath);
306 }
307 else
308 throw new XmlImportException("XPath expression expected instead of " . $this->tokens[$this->index + 1]->getKind());
309 if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
310 $this->index++;
311 else
312 throw new XmlImportException("Close brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
313 return $xpath;
314 }
315
316 /**
317 * Parses WITH clause
318 *
319 * @return XmlImportAstWith
320 */
321 private function parseWith()
322 {
323 $xpath = $this->parseXPathDependant();
324 //store sequence exit
325 array_push($this->clauseStack, XmlImportToken::KIND_ENDWITH);
326 return new XmlImportAstWith($xpath, $this->parseSequence());
327 }
328
329 /**
330 * Parses FOREACH clause
331 *
332 * @return XmlImportAstForeach
333 */
334 private function parseForeach()
335 {
336 $xpath = $this->parseXPathDependant();
337
338 array_push($this->clauseStack, XmlImportToken::KIND_ENDFOREACH);
339 return new XmlImportAstForeach($xpath, $this->parseSequence());
340 }
341
342 /**
343 * Parses IF clause
344 *
345 * @return XmlImportAstIf
346 */
347 private function parseIf()
348 {
349 $this->index++;
350 $this->elseAllowed = true;
351 array_push($this->clauseStack, XmlImportToken::KIND_ENDIF);
352
353 if ($this->index + 1 == count($this->tokens))
354 throw new XmlImportException("Reached end of template but expression was expected");
355
356 if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_OPEN)
357 $this->index++;
358 else
359 throw new XmlImportException("Open brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
360 $if = new XmlImportAstIf($this->parseExpression());
361 if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
362 $this->index++;
363 else
364 throw new XmlImportException("Close brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
365 $if->addIfBody($this->parseSequence());
366 if ($this->index + 1 != count($this->tokens))
367 {
368 while ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_ELSEIF)
369 {
370 $this->index++;
371 if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_OPEN)
372 $this->index++;
373 else
374 throw new XmlImportException("Open brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
375 $condition = $this->parseExpression();
376 if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
377 $this->index++;
378 else
379 throw new XmlImportException("Close brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
380 $elseif = new XmlImportAstElseif($condition, $this->parseSequence());
381 $if->addElseif($elseif);
382 if ($this->index + 1 == count($this->tokens))
383 break;
384 }
385 if ($this->index + 1 < count($this->tokens) && $this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_ELSE)
386 {
387 $this->index++;
388 $if->addElseBody($this->parseSequence());
389 }
390 }
391 return $if;
392 }
393 }