%PDF- %PDF-
Direktori : /proc/self/root/home/bitrix/www/bitrix/modules/main/lib/web/dom/ |
Current File : //proc/self/root/home/bitrix/www/bitrix/modules/main/lib/web/dom/queryselectorengine.php |
<?php namespace Bitrix\Main\Web\DOM; class QuerySelectorEngine extends QueryEngine { const PATH_CODE_NAME = 'name'; const PATH_CODE_CHILD = 'child'; const PATH_CODE_CLASS = 'class'; const PATH_CODE_DESCENDANT = 'descendant'; const PATH_CODE_ATTR = 'attr'; const PATH_CODE_PSEUDO = 'pseudo'; public function query($queryString = "", Node $node, $limit = 0, $direction = self::DIR_DOWN) { //TODO: use children property $instructionList = $this->parseQueryString($queryString); if(count($instructionList) <= 0) { return array(); } return $this->queryInternal($instructionList, $node, $limit, $direction); } public function queryInternal(array $instructionList, Node $node, $limit = 0, $direction = self::DIR_DOWN) { $resultList = array(); //echo "Instructions: ".print_R($instructionList, true); $filter = array(); $isFilterOnlyChildList = null; $length = count($instructionList); for($i = 0; $i < $length; $i++) { $instruction = $instructionList[$i]; switch($instruction['code']) { case self::PATH_CODE_NAME: $filter[] = array(QueryEngine::FILTER_NODE_NAME => $instruction['value']); break; case self::PATH_CODE_CLASS: $filter[] = array(QueryEngine::FILTER_ATTR_CLASS_NAME => $instruction['value']); break; case self::PATH_CODE_ATTR: $attrInstruction = $instruction['value']; if(isset($attrInstruction['value'])) { $filter[] = array(QueryEngine::FILTER_ATTR_VALUE => array($attrInstruction)); } else { $filter[] = array(QueryEngine::FILTER_ATTR => $attrInstruction['name']); } break; case self::PATH_CODE_DESCENDANT: $isFilterOnlyChildList = false; break 2; case self::PATH_CODE_CHILD: $isFilterOnlyChildList = true; break 2; default: //throw new \Bitrix\Main\NotSupportedException('Not supported instruction ' . $instruction['code']); return array(); } } if(count($filter) <= 0) { return $resultList; } //echo "Filter: ".print_R($filter, true); if($i >= $length) { return $this->walk($filter, null, $node, $limit); } else { $findNodeList = array(); if($isFilterOnlyChildList) { foreach($node->getChildNodesArray() as $findNode) { if($this->isNodeFiltered($findNode, $filter)) { $findNodeList[] = $findNode; } } } else { $this->limit = null; $this->deep = false; $this->direction = $direction; $findNodeList = $this->walkInternal($filter, null, $node); //echo "findNodeList: " . count($findNodeList) . "\n\n\n"; } } if(count($findNodeList) <= 0) { return $resultList; } $childInstructionList = array(); while(++$i < $length) { $childInstructionList[] = $instruction = $instructionList[$i]; } if(count($childInstructionList) <= 0) { return $resultList; } foreach($findNodeList as $findNode) { $resultList = array_merge( $resultList, $this->queryInternal($childInstructionList, $findNode, $limit, $direction) ); } return $resultList; } public function parseQueryStringPseudo($string) { return ''; } public function parseQueryStringAttr($string) { static $operations = array('~', '|', '^', '$', '*', '=', '!'); $result = array(); $list = explode('=', $string); if(isset($list[1])) { $operation = substr($list[0], -1); if(in_array($operation, $operations)) { $result['name'] = trim(substr($list[0], 0, -1)); $result['operation'] = $operation; } else { $result['name'] = trim($list[0]); $result['operation'] = '='; } $result['value'] = trim($list[1], "'\" \t\n\r\0\x0B"); } else { $result['name'] = trim($list[0]); } return $result; } /** * @param string $string * @return array */ public function parseQueryString($string) { static $dividers = array('*', '#', '.', ' ', '>', '<', '[', ':'); $path = array(); $string = trim($string); $length = strlen($string); $i = 0; while($i < $length) { $operator = ''; $char = substr($string, $i, 1); switch($char) { case '#': $operator = self::PATH_CODE_ATTR; $buffer = $this->writeToBuffer($string, $length, $i, $dividers); $path[] = array( 'code' => $operator, 'value' => array( 'name' => 'id', 'operation' => '=', 'value' => $buffer ) ); break; case '.': $operator = self::PATH_CODE_CLASS; $buffer = $this->writeToBuffer($string, $length, $i, $dividers); $path[] = array('code' => $operator, 'value' => $buffer); break; case ' ': $operator = self::PATH_CODE_DESCENDANT; $path[] = array('code' => $operator, 'value' => ''); ++$i; break; case '>': $operator = self::PATH_CODE_CHILD; $path[] = array('code' => $operator, 'value' => ''); ++$i; break; case '<': $path[] = array('code' => $operator, 'value' => ''); ++$i; break; case ':': $operator = self::PATH_CODE_PSEUDO; $buffer = $this->writeToBuffer($string, $length, $i, $dividers); $path[] = array('code' => $operator, 'value' => $this->parseQueryStringPseudo($buffer)); break; case '[': $operator = self::PATH_CODE_ATTR; $buffer = $this->writeToBuffer($string, $length, $i, [']']); $path[] = array('code' => $operator, 'value' => $this->parseQueryStringAttr($buffer)); ++$i; break; default: //throw new DomException('Wrong QuerySelector string'); $operator = self::PATH_CODE_NAME; $buffer = $char; $buffer .= $this->writeToBuffer($string, $length, $i, $dividers); $path[] = array('code' => $operator, 'value' => $buffer); } } return $path; } /** * @param string $string * @param int $length * @param int $i * @param array $dividers * @return string */ protected function writeToBuffer($string, $length, &$i, array $dividers) { $buffer = ''; $escapeNext = false; while(++$i < $length) { $char = substr($string, $i, 1); if($char === '\\') { if($escapeNext) { $buffer = substr($buffer, 0, -1); $escapeNext = false; } else { $escapeNext = true; } } elseif(in_array($char, $dividers)) { if($escapeNext) { $buffer = substr($buffer, 0, -1); $escapeNext = false; } else { break; } } else { $escapeNext = false; } $buffer .= $char; } return $buffer; } }