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 / XmlImportTemplateScanner.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
XmlImportTemplateScanner.php
403 lines
1 <?php
2 /**
3 * @author Olexandr Zanichkovsky <olexandr.zanichkovsky@zophiatech.com>
4 * @package General
5 */
6
7 require_once dirname(__FILE__) . '/XmlImportToken.php';
8 require_once dirname(__FILE__) . '/XmlImportException.php';
9
10 /**
11 * Used to scan string into a list of tokens
12 */
13 final class XmlImportTemplateScanner
14 {
15 /**
16 * Language keywords
17 *
18 * @var array
19 */
20 private $keywords = array(
21 'IF',
22 'ELSEIF',
23 'ELSE',
24 'ENDIF',
25 'FOREACH',
26 'ENDFOREACH',
27 'WITH',
28 'ENDWITH',
29 'MATH'
30 );
31
32 /**
33 * Parsing text
34 */
35 const STATE_TEXT = 'STATE_TEXT';
36
37 /**
38 * Parsing XPath
39 */
40 const STATE_XPATH = 'STATE_XPATH';
41
42 /**
43 * Parsing Language
44 */
45 const STATE_LANG = 'STATE_LANG';
46
47 /**
48 * Whether it is lang block start
49 *
50 * @var bool
51 */
52 private $isLangBegin = false;
53
54 /**
55 * Current parsing state
56 *
57 * @var string
58 */
59 private $currentState = XmlImportTemplateScanner::STATE_TEXT;
60
61 /**
62 * Scans template from XmlImportReaderInterface and returns the list of tokens
63 *
64 * @param XmlImportReaderInterface $input
65 * @return array
66 */
67 public function scan(XmlImportReaderInterface $input)
68 {
69 $results = array();
70 while (($ch = $input->peek()) !== false)
71 {
72 switch ($this->currentState)
73 {
74 case XmlImportTemplateScanner::STATE_TEXT:
75 if ($ch == '[')
76 {
77 $this->currentState = XmlImportTemplateScanner::STATE_LANG;
78 $this->isLangBegin = true;
79 //omit [
80 $input->read();
81 }
82 elseif ($ch == '{')
83 {
84 $this->currentState = XmlImportTemplateScanner::STATE_XPATH;
85 //omit {
86 $input->read();
87 }
88 else
89 {
90 $results[] = $this->scanText($input);
91 }
92 break;
93 case XmlImportTemplateScanner::STATE_XPATH:
94 $results = array_merge($results, $this->scanXPath($input, false));
95 break;
96 case XmlImportTemplateScanner::STATE_LANG:
97 $ch = $input->peek();
98
99 if (preg_match('/\s/', $ch))
100 {
101 //omit space
102 $input->read();
103 }
104 elseif (preg_match('/[_a-z]/i', $ch))
105 {
106 $result = $this->scanName($input);
107 if (is_array($result))
108 $results = array_merge($results, $result);
109 else
110 $results[] = $result;
111 }
112 elseif (preg_match('/(\d|-)/', $ch))
113 {
114 $result = $this->scanNumber($input);
115 if (is_array($result))
116 $results = array_merge($results, $result);
117 else
118 $results[] = $result;
119 }
120 elseif ($ch == "+" || $ch == "-" || $ch == "/" || $ch == "*")
121 {
122 $this->isLangBegin = false;
123 $input->read();
124 $results[] = new XmlImportToken(XmlImportToken::KIND_OPERATION, $ch);
125 }
126 elseif ($ch == '"')
127 {
128 //omit "
129 $input->read();
130 $result = $this->scanString($input);
131 if (is_array($result))
132 $results = array_merge($results, $result);
133 else
134 $results[] = $result;
135 }
136 elseif ($ch == '{')
137 {
138 $input->read();
139 $result = $this->scanXPath($input);
140 if (is_array($result))
141 $results = array_merge($results, $result);
142 else
143 $results[] = $result;
144 }
145 elseif ($ch == '(')
146 {
147 $this->isLangBegin = false;
148 $input->read();
149 $results[] = new XmlImportToken(XmlImportToken::KIND_OPEN);
150 }
151 elseif ($ch == ')')
152 {
153 $this->isLangBegin = false;
154 $input->read();
155 $results[] = new XmlImportToken(XmlImportToken::KIND_CLOSE);
156 }
157 elseif ($ch == ',')
158 {
159 $this->isLangBegin = false;
160 $input->read();
161 $results[] = new XmlImportToken(XmlImportToken::KIND_COMMA);
162 }
163 elseif ($ch == ']')
164 {
165 $this->isLangBegin = false;
166 $this->currentState = XmlImportTemplateScanner::STATE_TEXT;
167 //omit ]
168 $input->read();
169 }
170 else
171 throw new XmlImportException("Unexpected symbol '$ch'");
172
173 break;
174 }
175 }
176
177 return $results;
178 }
179
180 /**
181 * Scans text
182 *
183 * @param XmlImportReaderInterface $input
184 * @return XmlImportToken
185 */
186 private function scanText($input)
187 {
188 $accum = $input->read();
189 while (($ch = $input->peek()) !== false)
190 {
191 if ($ch == '{' && $accum[strlen($accum) - 1] != "\\")
192 {
193 $this->currentState = XmlImportTemplateScanner::STATE_XPATH;
194 //omit {
195 $input->read();
196 break;
197 }
198 elseif ($ch == '[' && $accum[strlen($accum) - 1] != "\\")
199 {
200 $this->currentState = XmlImportTemplateScanner::STATE_LANG;
201 $this->isLangBegin = true;
202 //omit [
203 $input->read();
204 break;
205 }
206 else
207 $accum .= $input->read();
208 }
209 $accum = str_replace(array("\\[", "\\{"), array('[', '{'), $accum);
210 return new XmlImportToken(XmlImportToken::KIND_TEXT, $accum);
211 }
212
213 /**
214 * Scans XPath
215 *
216 * @param XmlImportReaderInterface $input
217 * @param bool $insideLang
218 * @return XmlImportToken
219 */
220 private function scanXPath($input, $insideLang = true)
221 {
222 $accum = '';
223 while(($ch = $input->peek()) !== false)
224 {
225 if ($ch == '}' && (strlen($accum) == 0 || $accum[strlen($accum) - 1] != "\\"))
226 {
227 //skip }
228 $input->read();
229 $accum = str_replace("\\}", '}', $accum);
230 if ($insideLang)
231 {
232 if ($this->isLangBegin)
233 {
234 return array(new XmlImportToken(XmlImportToken::KIND_PRINT), new XmlImportToken(XmlImportToken::KIND_XPATH, $accum));
235 }
236 else
237 return new XmlImportToken(XmlImportToken::KIND_XPATH, $accum);
238 }
239 else
240 {
241 $this->currentState = XmlImportTemplateScanner::STATE_TEXT;
242
243 return array(new XmlImportToken(XmlImportToken::KIND_PRINT), new XmlImportToken(XmlImportToken::KIND_XPATH, $accum));
244 }
245 }
246 else
247 $accum .= $input->read();
248 }
249 throw new XmlImportException('Unexpected end of XPath expression \'' . $accum . '\'');
250 }
251
252 /**
253 * Scans name
254 *
255 * @param XmlImportReaderInterface $input
256 * @return XmlImportToken
257 */
258 private function scanName(XmlImportReaderInterface $input)
259 {
260 $accum = $input->read();
261 while (preg_match('/[_a-z0-9]/i', $input->peek()))
262 {
263 $accum .= $input->read();
264 if ($input->peek() === false)
265 throw new XmlImportException("Unexpected end of function or keyword name \"$accum\"");
266 }
267 if (in_array(strtoupper($accum), $this->keywords))
268 {
269 return new XmlImportToken(strtoupper($accum));
270 }
271 else
272 {
273 if ($this->isLangBegin)
274 {
275 $this->isLangBegin = false;
276 return array(new XmlImportToken(XmlImportToken::KIND_PRINT), new XmlImportToken(XmlImportToken::KIND_FUNCTION, $accum));
277 }
278 else
279 return new XmlImportToken(XmlImportToken::KIND_FUNCTION, $accum);
280 }
281 }
282
283 /**
284 * Scans string literal
285 *
286 * @param XmlImportReaderInterface $input
287 * @return XmlImportToken
288 */
289 private function scanString(XmlImportReaderInterface $input)
290 {
291 $accum = '';
292 while(($ch = $input->peek()) !== false)
293 {
294 if ($ch == '"' && (strlen($accum) == 0 || $accum[strlen($accum) - 1] != "\\"))
295 {
296 //skip "
297 $input->read();
298 $accum = str_replace("\\\"", '"', $accum);
299 if ($this->isLangBegin)
300 {
301 $this->isLangBegin = false;
302 return array(new XmlImportToken(XmlImportToken::KIND_PRINT), new XmlImportToken(XmlImportToken::KIND_STRING, $accum));
303 }
304 else
305 {
306 return new XmlImportToken(XmlImportToken::KIND_STRING, $accum);
307 }
308 }
309 else
310 $accum .= $input->read();
311 }
312 throw new XmlImportException('Unexpected end of string literal "' . $accum . '"');
313 }
314
315 /**
316 * Scans number
317 *
318 * @param XmlImportReaderInterface $input
319 * @return XmlImportToken
320 */
321 private function scanNumber(XmlImportReaderInterface $input)
322 {
323 $isInt = true;
324 $accum = $this->scanInt($input);
325 if ($input->peek() == '.')
326 {
327 $isInt = false;
328 $accum .= $input->read();
329 $accum .= $this->scanNumberFrac($input);
330 }
331 if (strtolower($input->peek()) == 'e' )
332 {
333 $isInt = false;
334 $accum .= $input->read();
335 $accum .= $this->scanInt($input);
336 }
337 if ($isInt)
338 {
339 if ($this->isLangBegin)
340 {
341 $this->isLangBegin = false;
342 return array(new XmlImportToken(XmlImportToken::KIND_PRINT), new XmlImportToken(XmlImportToken::KIND_INT, intval($accum)));
343 }
344 else
345 {
346 return new XmlImportToken(XmlImportToken::KIND_INT, intval($accum));
347 }
348 }
349 else
350 {
351 if ($this->isLangBegin)
352 {
353 $this->isLangBegin = false;
354 return array(new XmlImportToken(XmlImportToken::KIND_PRINT), new XmlImportToken(XmlImportToken::KIND_FLOAT, floatval($accum)));
355 }
356 else
357 {
358 return new XmlImportToken(XmlImportToken::KIND_FLOAT, floatval($accum));
359 }
360 }
361 }
362
363 /**
364 * Scans integer number
365 *
366 * @param XmlImportReaderInterface $input
367 * @return string
368 */
369 private function scanInt(XmlImportReaderInterface $input)
370 {
371 if (preg_match('/(\d|-)/', $input->peek()))
372 {
373 $accum = $input->read();
374 if ($accum == '-' && !preg_match('/\d/', $input->peek()))
375 throw new XmlImportException("Expected digit after a minus");
376 while (preg_match('/\d/', $input->peek()))
377 {
378 $accum .= $input->read();
379 }
380 return $accum;
381 }
382 else
383 throw new XmlImportException("digit or '-' expected in a number");
384 }
385
386 /**
387 * Scans fraction part of a number
388 *
389 * @param XmlImportReaderInterface $input
390 * @return string
391 */
392 private function scanNumberFrac(XmlImportReaderInterface $input)
393 {
394 $accum = '';
395 while (preg_match('/\d/', $input->peek()))
396 {
397 $accum .= $input->read();
398 }
399 if (strlen($accum) == 0)
400 throw new XmlImportException("Digits are expected after a '.'");
401 return $accum;
402 }
403 }