Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
queryselectorengine.php
1<?php
2namespace Bitrix\Main\Web\DOM;
3
5{
6 const PATH_CODE_NAME = 'name';
7 const PATH_CODE_CHILD = 'child';
8 const PATH_CODE_CLASS = 'class';
9 const PATH_CODE_DESCENDANT = 'descendant';
10 const PATH_CODE_ATTR = 'attr';
11 const PATH_CODE_PSEUDO = 'pseudo';
12
13
14 public function query($queryString = "", Node $node, $limit = 0, $direction = self::DIR_DOWN)
15 {
16 //TODO: use children property
17 $instructionList = $this->parseQueryString($queryString);
18 if(empty($instructionList))
19 {
20 return array();
21 }
22
23 return $this->queryInternal($instructionList, $node, $limit, $direction);
24 }
25
26 public function queryInternal(array $instructionList, Node $node, $limit = 0, $direction = self::DIR_DOWN)
27 {
28 $resultList = array();
29 //echo "Instructions: ".print_R($instructionList, true);
30 $filter = array();
31
32 $isFilterOnlyChildList = null;
33
34 $length = count($instructionList);
35 for($i = 0; $i < $length; $i++)
36 {
37 $instruction = $instructionList[$i];
38 switch($instruction['code'])
39 {
41
42 $filter[] = array(QueryEngine::FILTER_NODE_NAME => $instruction['value']);
43 break;
44
46
47 $filter[] = array(QueryEngine::FILTER_ATTR_CLASS_NAME => $instruction['value']);
48 break;
49
51
52 $attrInstruction = $instruction['value'];
53 if(isset($attrInstruction['value']))
54 {
55 $filter[] = array(QueryEngine::FILTER_ATTR_VALUE => array($attrInstruction));
56 }
57 else
58 {
59 $filter[] = array(QueryEngine::FILTER_ATTR => $attrInstruction['name']);
60 }
61
62 break;
63
65
66 $isFilterOnlyChildList = false;
67 break 2;
68
70
71 $isFilterOnlyChildList = true;
72 break 2;
73
74 default:
75
76 //throw new \Bitrix\Main\NotSupportedException('Not supported instruction ' . $instruction['code']);
77 return array();
78 }
79
80 }
81
82 if(empty($filter))
83 {
84 return $resultList;
85 }
86
87 //echo "Filter: ".print_R($filter, true);
88
89
90 if($i >= $length)
91 {
92 return $this->walk($filter, null, $node, $limit);
93 }
94 else
95 {
96 $findNodeList = array();
97 if($isFilterOnlyChildList)
98 {
99 foreach($node->getChildNodesArray() as $findNode)
100 {
101 if($this->isNodeFiltered($findNode, $filter))
102 {
103 $findNodeList[] = $findNode;
104 }
105 }
106 }
107 else
108 {
109 $this->limit = null;
110 $this->deep = false;
111 $this->direction = $direction;
112 $findNodeList = $this->walkInternal($filter, null, $node);
113 //echo "findNodeList: " . count($findNodeList) . "\n\n\n";
114 }
115 }
116
117 if(empty($findNodeList))
118 {
119 return $resultList;
120 }
121
122
123 $childInstructionList = array();
124 while(++$i < $length)
125 {
126 $childInstructionList[] = $instruction = $instructionList[$i];
127 }
128
129 if(empty($childInstructionList))
130 {
131 return $resultList;
132 }
133
134 foreach($findNodeList as $findNode)
135 {
136 $resultList = array_merge(
137 $resultList,
138 $this->queryInternal($childInstructionList, $findNode, $limit, $direction)
139 );
140 }
141
142
143 return $resultList;
144 }
145
146 public function parseQueryStringPseudo($string)
147 {
148 return '';
149 }
150
151 public function parseQueryStringAttr($string)
152 {
153 static $operations = array('~', '|', '^', '$', '*', '=', '!');
154
155 $result = array();
156 $list = explode('=', $string);
157
158 if(isset($list[1]))
159 {
160 $operation = mb_substr($list[0], -1);
161 if(in_array($operation, $operations))
162 {
163 $result['name'] = trim(mb_substr($list[0], 0, -1));
164 $result['operation'] = $operation;
165 }
166 else
167 {
168 $result['name'] = trim($list[0]);
169 $result['operation'] = '=';
170 }
171
172 $result['value'] = trim($list[1], "'\" \t\n\r\0\x0B");
173 }
174 else
175 {
176 $result['name'] = trim($list[0]);
177 }
178
179 return $result;
180 }
181
186 public function parseQueryString($string)
187 {
188 static $dividers = array('*', '#', '.', ' ', '>', '<', '[', ':');
189 $path = array();
190
191 $string = trim($string);
192 $length = mb_strlen($string);
193
194 $i = 0;
195 while($i < $length)
196 {
197 $operator = '';
198
199 $char = mb_substr($string, $i, 1);
200 switch($char)
201 {
202 case '#':
203 $operator = self::PATH_CODE_ATTR;
204 $buffer = $this->writeToBuffer($string, $length, $i, $dividers);
205 $path[] = array(
206 'code' => $operator,
207 'value' => array(
208 'name' => 'id',
209 'operation' => '=',
210 'value' => $buffer
211 )
212 );
213 break;
214
215 case '.':
216 $operator = self::PATH_CODE_CLASS;
217 $buffer = $this->writeToBuffer($string, $length, $i, $dividers);
218 $path[] = array('code' => $operator, 'value' => $buffer);
219 break;
220
221 case ' ':
222 $operator = self::PATH_CODE_DESCENDANT;
223 $path[] = array('code' => $operator, 'value' => '');
224 ++$i;
225 break;
226
227 case '>':
228 $operator = self::PATH_CODE_CHILD;
229 $path[] = array('code' => $operator, 'value' => '');
230 ++$i;
231 break;
232
233 case '<':
234 $path[] = array('code' => $operator, 'value' => '');
235 ++$i;
236 break;
237
238 case ':':
239 $operator = self::PATH_CODE_PSEUDO;
240 $buffer = $this->writeToBuffer($string, $length, $i, $dividers);
241 $path[] = array('code' => $operator, 'value' => $this->parseQueryStringPseudo($buffer));
242 break;
243
244 case '[':
245 $operator = self::PATH_CODE_ATTR;
246 $buffer = $this->writeToBuffer($string, $length, $i, [']']);
247 $path[] = array('code' => $operator, 'value' => $this->parseQueryStringAttr($buffer));
248 ++$i;
249 break;
250
251 default:
252 //throw new DomException('Wrong QuerySelector string');
253 $operator = self::PATH_CODE_NAME;
254 $buffer = $char;
255 $buffer .= $this->writeToBuffer($string, $length, $i, $dividers);
256 $path[] = array('code' => $operator, 'value' => $buffer);
257 }
258 }
259
260 return $path;
261 }
262
270 protected function writeToBuffer($string, $length, &$i, array $dividers)
271 {
272 $buffer = '';
273 $escapeNext = false;
274
275 while(++$i < $length)
276 {
277 $char = mb_substr($string, $i, 1);
278 if($char === '\\')
279 {
280 if($escapeNext)
281 {
282 $buffer = mb_substr($buffer, 0, -1);
283 $escapeNext = false;
284 }
285 else
286 {
287 $escapeNext = true;
288 }
289 }
290 elseif(in_array($char, $dividers))
291 {
292 if($escapeNext)
293 {
294 $buffer = mb_substr($buffer, 0, -1);
295 $escapeNext = false;
296 }
297 else
298 {
299 break;
300 }
301 }
302 else
303 {
304 $escapeNext = false;
305 }
306
307 $buffer .= $char;
308 }
309
310 return $buffer;
311 }
312}
walk(array $filter=null, callable $callback=null, Node $node, $limit=0, $direction=self::DIR_DOWN)
isNodeFiltered(Node $node, array $filter)
walkInternal(array $filter=null, callable $callback=null, Node $node)
queryInternal(array $instructionList, Node $node, $limit=0, $direction=self::DIR_DOWN)
writeToBuffer($string, $length, &$i, array $dividers)
query($queryString="", Node $node, $limit=0, $direction=self::DIR_DOWN)