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