/** * Translates CSS into XPath. * * @param string|array $locator current selector locator * * @return string */ public function translateToXPath($locator) { if (!is_string($locator)) { throw new \InvalidArgumentException('The CssSelector expects to get a string as locator'); } // Symfony 2.8+ API if (class_exists('Symfony\\Component\\CssSelector\\CssSelectorConverter')) { $converter = new CssSelectorConverter(); return $converter->toXPath($locator); } // old static API for Symfony 2.7 and older return CSS::toXPath($locator); }
/** * @param \DOMNode $node * @param string $selector * @return \DOMNodeList */ public function findAll($node, $selector) { $domXPath = new \DOMXPath($node->ownerDocument); $converter = new CssSelectorConverter(); $xpath = $converter->toXPath($selector); return $domXPath->query($xpath, $node); }
/** * Ensures that attributes can be placed for form element label. */ public function testAttributes() { $render_array = [ '#type' => 'label', '#attributes' => ['class' => ['kitten']], '#title' => 'Kittens', '#title_display' => 'above', ]; $css_selector_converter = new CssSelectorConverter(); $this->render($render_array); $elements = $this->xpath($css_selector_converter->toXPath('.kitten')); $this->assertCount(1, $elements); }
public function toXpath($selector, $contextMode = self::CONTEXT_CHILDREN, $isHtml = FALSE) { $converter = new CssSelectorConverter($isHtml); $result = $converter->toXPath($selector); switch ($contextMode) { case self::CONTEXT_DOCUMENT: $result = '//' . $result; break; case self::CONTEXT_CHILDREN: $result = './' . $result; break; } return $result; }
public function toXPath() { try { if (class_exists('Symfony\\Component\\CssSelector\\CssSelectorConverter')) { $converter = new CssSelectorConverter(); $query = $converter->toXPath($this->selector); } else { $query = CssSelector::toXPath($this->selector); } } catch (ExceptionInterface $e) { $query = null; } return $query; }
/** * select multiple elements from dom using css style selectors * @param string $selector * @return NodeCollection */ public function querySelectorAll($selector) { $converter = new CssSelectorConverter(); $xpathQuery = $converter->toXPath($selector); $results = $this->xpath->query($xpathQuery); if (!$results->item(0)) { return []; } $return = new NodeCollection(); for ($i = 0; $i < $results->length; $i++) { $node = new Node($results->item($i)); $return->append($node); } return $return; }
/** * @param string $cssExpr * @return string */ public function convertToXpath($cssExpr) { preg_match('!(.+) (@.+|.+\\(\\))$!', $cssExpr, $data); if (empty($data[2])) { return parent::toXPath($cssExpr); } return parent::toXPath($data[1]) . '/' . $data[2]; }
public function query($selector) { $selector = trim($selector); $converter = new CssSelectorConverter(); $prefix = '//'; if ($selector[0] == '>') { $selector = trim(substr($selector, 1)); $prefix = ''; } $xPath = $converter->toXPath($selector, $prefix); $parser = new \DOMXPath($this->getDocument()); $nodeList = []; foreach ($this->nodeList as $node) { $nodeList = array_merge($nodeList, iterator_to_array($parser->query($xPath, $node))); } $className = get_class($this); return (new $className())->fromNodeList($nodeList); }
public function matchesNode($node) { $matches_node = parent::matchesNode($node); if ($matches_node && $this->childSelector) { $matches_node = false; if ($node->hasChildNodes()) { foreach ($node->childNodes as $child) { $domXPath = new \DOMXPath($child->ownerDocument); $converter = new CssSelectorConverter(); $xpath = $converter->toXPath($this->childSelector); $results = $domXPath->query($xpath, $node); foreach ($results as $result) { if ($result === $child) { $matches_node = true; } } } } } return $matches_node; }
public static function toXPath($selector) { if (isset(self::$compiled[$selector])) { return self::$compiled[$selector]; } // Select DOMText if ($selector === 'text') { return '//text()'; } // Select DOMComment if ($selector === 'comment') { return '//comment()'; } if (!class_exists('Symfony\\Component\\CssSelector\\CssSelectorConverter')) { throw new \RuntimeException('Unable to filter with a CSS selector as the Symfony CssSelector 2.8+ is not installed (you can use filterXPath instead).'); } $converter = new CssSelectorConverter(true); $xPathQuery = $converter->toXPath($selector); self::$compiled[$selector] = $xPathQuery; return $xPathQuery; }
public function doValidation(Response $response) { $domDocument = new \DOMDocument(); @$domDocument->loadHTML((string) $response->getBody()); $domXPath = new \DOMXPath($domDocument); $error = false; $snotFoundSelectors = array(); foreach ($this->cssSelectors as $selector) { $converter = new CssSelectorConverter(); $selectorAsXPath = $converter->toXPath($selector['pattern']); $count = $domXPath->query($selectorAsXPath)->length; if ($count === 0) { $error = true; $snotFoundSelectors[] = $selector['pattern']; } } if ($error === true) { $allNotFoundSelectors = implode('", "', $snotFoundSelectors); throw new ValidationFailedException('CSS Selector "' . $allNotFoundSelectors . '" not found in DOM.'); } }
protected function compare() { $bench = new Ubench(); $url = 'tests/templated-retrospect/index.html'; $file = 'test.html'; if (!file_exists($file)) { $htmlstr = file_get_contents($url); file_put_contents($file, $htmlstr); } $htmlstr = file_get_contents($file); $this->log('', true); $this->log('Measuring Simple HTML DOM Parser...'); $resultsSimpleHtmlDomParser = $bench->run(function ($htmlstr) { $results = []; $html = HtmlDomParser::str_get_html($htmlstr); $html->find('title', 0)->innertext('New Title'); $results[1] = $html->__toString(); $tpl = HtmlDomParser::str_get_html(file_get_contents('tests/templated-retrospect/index.html')); foreach ($tpl->find('link') as $elem) { $elem->href = '//localhost/xparser/tests/templated-retrospect/' . $elem->href; } foreach ($tpl->find('img, script') as $elem) { $elem->src = '//localhost/xparser/tests/templated-retrospect/' . $elem->src; } $results[2] = $tpl->__toString(); return $results; }, $htmlstr); //$this->log('distance: ' . similar_text($htmlstr, $result)); $this->logBench($bench); $this->log('', true); $this->log('Measuring XParser...'); $resultsXParser = $bench->run(function ($htmlstr) { $results = []; $html = new XNode($htmlstr); $html->find('title')->inner('New Title'); $results[1] = $html->__toString(); $tpl = new XNode(file_get_contents('tests/templated-retrospect/index.html')); foreach ($tpl('link') as $elem) { $elem->href = '//localhost/xparser/tests/templated-retrospect/' . $elem->href; } foreach ($tpl('img, script') as $elem) { $elem->src = '//localhost/xparser/tests/templated-retrospect/' . $elem->src; } $results[2] = $tpl->__toString(); return $results; }, $htmlstr); //$this->log('distance: ' . similar_text($htmlstr, $result)); $this->logBench($bench); $this->log('', true); $this->log('Measuring Ganon...'); $resultsGanon = $bench->run(function ($htmlstr) { $html = str_get_dom($htmlstr); foreach ($html('title') as $title) { $title->setInnerText('New Title'); } $results[1] = $html->__toString(); $tpl = new XNode(file_get_contents('tests/templated-retrospect/index.html')); foreach ($tpl('link') as $elem) { $elem->href = '//localhost/xparser/tests/templated-retrospect/' . $elem->href; } foreach ($tpl('img, script') as $elem) { $elem->src = '//localhost/xparser/tests/templated-retrospect/' . $elem->src; } $results[2] = $tpl->__toString(); return $results; }, $htmlstr); //$this->log('distance: ' . similar_text($htmlstr, $result)); $this->logBench($bench); $this->log('', true); $this->log('Symfony CSS Selector combined with DOMDocument and DOMXPath...'); $resultsXParser = $bench->run(function ($htmlstr) { $results = []; $html = new DOMDocument(); libxml_use_internal_errors(true); $html->loadHTML($htmlstr); $converter = new CssSelectorConverter(); $xpath = new DOMXPath($html); $elements = $xpath->query($converter->toXPath('title')); foreach ($elements as $element) { $element->innserHTML = 'New Title'; } $results[1] = $html->saveHTML(); $tpl = new DOMDocument(); $tpl->load('tests/templated-retrospect/index.html'); foreach ($xpath->query($converter->toXPath('link')) as $elem) { $elem->setAttribute('href', '//localhost/xparser/tests/templated-retrospect/' . $elem->getAttribute('href')); } foreach ($xpath->query($converter->toXPath('img, script')) as $elem) { $elem->setAttribute('src', '//localhost/xparser/tests/templated-retrospect/' . $elem->getAttribute('src')); } $results[2] = $tpl->saveHTML(); return $results; }, $htmlstr); //$this->log('distance: ' . similar_text($htmlstr, $result)); $this->logBench($bench); $this->log('', true); $this->log('Simple HTML DOM Parser vs Ganon distance: ' . similar_text($resultsSimpleHtmlDomParser[2], $resultsGanon[2])); $this->log('Simple HTML DOM Parser vs XParser distance: ' . similar_text($resultsSimpleHtmlDomParser[2], $resultsXParser[2])); $this->log('Ganon vs XParser distance: ' . similar_text($resultsGanon[2], $resultsXParser[2])); $this->log('', true); $this->log('', true); }
/** * Return the xpath representaiton of the selector, using the appropriate method * @return string */ public function xpath() { if (!$this->_xpath) { $ccv = new CssSelectorConverter(true); switch ($this->type()) { case 'css': $this->_xpath = '//' . $ccv->toXPath($this->selector()); break; case 'xpath': $this->_xpath = $this->selector(); break; case 'field': $this->_xpath = $this->field_to_xpath($this->selector()); break; case 'label': $this->_xpath = $this->label_to_xpath($this->selector()); break; case 'link': $this->_xpath = $this->link_to_xpath($this->selector()); break; case 'button': $this->_xpath = $this->button_to_xpath($this->selector()); break; default: throw new Exception('Locator type ":type" does not exist', array(':type' => $this->_type)); } } return $this->_xpath; }
/** * @dataProvider getCssToXPathWithoutPrefixTestData */ public function testCssToXPathWithoutPrefix($css, $xpath) { $converter = new CssSelectorConverter(); $this->assertEquals($xpath, $converter->toXPath($css, ''), '->parse() parses an input string and returns a node'); }
/** * @param string $selectors CSS selector(s) * @param string $prefix * @return HTMLCollection */ private function css(string $selectors, string $prefix = "descendant-or-self::") : HTMLCollection { $converter = new CssSelectorConverter(); $xPathSelector = $converter->toXPath($selectors, $prefix); return $this->xPath($xPathSelector); }
public function getXpath($query, $prefix = NULL) { $search = array('@<script[^>]*?>.*?</script>@si', '@<[\\/\\!]*?[^<>]*?>@si', '#:(contains|first|last|parent|gt|lt|submit|button|hidden|visible|has|eq)(?!-)\\b([\\(](.*?)[\\)])?#x'); '/<(' . $tag . '*)\\b([^>]*)>(?:(.*?)(<\\/\\1>))?/ix'; $query = preg_replace($search, '', $query); $x = new CssSelectorConverter(); $path = $x->toXPath($query, $prefix); //var_dump(func_get_arg(0).'=>'.$query); return $path; }
/** * Convert a CSS selector to XPath. * Uses Symfony CSS Selector 2.8 and above API if possible. * Otherwise fallback to pre-2.8 static interface. * * @param string $css_selector CSS selector * @return string XPath selector */ private function convert_css_selector_to_xpath($css_selector) { if (class_exists('Symfony\\Component\\CssSelector\\CssSelectorConverter')) { $converter = new CssSelector\CssSelectorConverter(); return $converter->toXPath($this->selector()); } return CssSelector\CssSelector::toXPath($this->selector()); }
/** * create XPath * * @param \DOMDocument $document * @param array $cssRules * * @return \DOMXPath */ private function createXPath(\DOMDocument $document, array $cssRules) { $propertyStorage = new \SplObjectStorage(); $xPath = new \DOMXPath($document); // any rules? if (0 !== count($cssRules)) { // loop rules foreach ($cssRules as $rule) { $ruleSelector = $rule['selector']; $ruleProperties = $rule['properties']; if (!$ruleSelector || !$ruleProperties) { continue; } try { $query = $this->cssConverter->toXPath($ruleSelector); } catch (ExceptionInterface $e) { $query = null; } // validate query if (null === $query) { continue; } // search elements $elements = $xPath->query($query); // validate elements if (false === $elements) { continue; } // loop found elements foreach ($elements as $element) { /** * @var $element \DOMElement */ if ($ruleSelector == '*' && ($element->tagName == 'html' || $element->tagName === 'title' || $element->tagName == 'meta' || $element->tagName == 'head' || $element->tagName == 'style' || $element->tagName == 'script' || $element->tagName == 'link')) { continue; } // no styles stored? if (!isset($propertyStorage[$element])) { // init var $originalStyle = $element->attributes->getNamedItem('style'); if ($originalStyle) { $originalStyle = $originalStyle->value; } else { $originalStyle = ''; } // store original styles $propertyStorage->attach($element, $originalStyle); // clear the styles $element->setAttribute('style', ''); } // set attribute $propertiesString = $this->createPropertyChunks($element, $ruleProperties); if ($propertiesString) { $element->setAttribute('style', $propertiesString); } } } foreach ($propertyStorage as $element) { $originalStyle = $propertyStorage->getInfo(); if ($originalStyle) { $originalStyles = $this->splitIntoProperties($originalStyle); $originalProperties = $this->splitStyleIntoChunks($originalStyles); // set attribute $propertiesString = $this->createPropertyChunks($element, $originalProperties); if ($propertiesString) { $element->setAttribute('style', $propertiesString); } } } } return $xPath; }
<?php require_once __DIR__ . DELIMITER_DIR . '/jqueryphpmanager.php'; require_once __DIR__ . '/abstracts/selector/CssSelectorConverter.php'; use Symfony\Component\CssSelector\CssSelectorConverter as CssSelector; CssSelector::autoload(); JqueryBoxManager::autoload(); $backtrace = debug_backtrace(); $namespaceTokens = isset($backtrace[2]) ? $backtrace[2] : NULL; if (isset($namespaceTokens['class'])) { JqueryBoxManager::setNamespace('Loader_' . $namespaceTokens['line'] . '_' . $namespaceTokens['class']); } self::$classes[self::$caller] = new JqueryBoxManager(); if (!defined('jqmdoc')) { define('jqmdoc', 'jqueryphp_abstracts_document'); } if (!defined('jqmel')) { define('jqmel', 'jqueryphp_abstracts_element'); } if (!defined('jqmnull')) { define('jqmnull', 'jqueryphp_abstracts_prevObject'); } if (!defined('jqmlist')) { define('jqmlist', 'jqueryphp_abstracts_nodelist'); } if (!defined('jqmwin')) { define('jqmwin', 'jqueryphp_abstracts_window'); } if (!function_exists('jqm')) { function jqm($input, $parent = '*') {
/** * Helper to convert css path to xpath using Symfony component. * * @param string $selector * CSS selector string. * * @return string * Xpath string. */ protected function cssToXpath($selector) { // Use CssSelector class from Symfony framework. if (!class_exists('Symfony\\Component\\CssSelector\\CssSelectorConverter')) { throw new Exception(t('Unable to load class Symfony\\Component\\CssSelector\\CssSelectorConverter')); } $converter = new CssSelectorConverter(); return $converter->toXpath($selector); }
/** * Returns a list of the elements within the document that match the specified group of selectors. * * @param string $filename CSS Selector * * @return DOMNodeList List of matching elements (will be empty if no matches are found). */ public function querySelectorAll($cssSelectors) { $xpathQuery = $this->converter->toXPath($cssSelectors); return $this->query($xpathQuery); }
}; $array2query = function ($new) { $arr = array(); foreach ($new as $k => $v) { $arr[] = $k . '=' . $v; } return implode('&', $arr); }; $new = $query2array($d['query'], 3); asort($new); return $d['scheme'] . '://' . $d['host'] . '/?' . $array2query($new) . '&url=' . $d['path']; } return '<pre>' . print_r(array('param' => $url, 'res' => urlT($url)), true) . '</pre>'; }); $app->get('/test3/', function () { $converter = new CssSelectorConverter(); return '<pre>' . $converter->toXPath('div.item > h4 > a') . '</pre>'; }); $app->post('/game.php', function (Request $request) { $game = new Game\GomokuGame(); $reset = $request->get('reset'); $x = $request->get('x'); $y = $request->get('y'); if (isset($reset) && !empty($reset)) { $game->reset(); return new JsonResponse(array('reset' => $reset)); } elseif ($x >= 0 && $y >= 0) { try { $game->makeMove((int) $x, (int) $y); $machineMove = $game->machineMove(); $game->checkWinner();
/** * Filters the list of nodes with a CSS selector. * * This method only works if you have installed the CssSelector Symfony Component. * * @param string $selector A CSS selector * * @return Crawler A new instance of Crawler with the filtered list of nodes * * @throws \RuntimeException if the CssSelector Component is not available */ public function filter($selector) { if (!class_exists('Symfony\\Component\\CssSelector\\CssSelectorConverter')) { throw new \RuntimeException('Unable to filter with a CSS selector as the Symfony CssSelector 2.8+ is not installed (you can use filterXPath instead).'); } $converter = new CssSelectorConverter($this->isHtml); // The CssSelector already prefixes the selector with descendant-or-self:: return $this->filterRelativeXPath($converter->toXPath($selector)); }
public function testCssToXPathXml() { $converter = new CssSelectorConverter(false); $this->assertEquals('descendant-or-self::H1', $converter->toXPath('H1')); }
private function findViaXPath($select, $html = null) { $document = new DOMDocument(); libxml_use_internal_errors(true); $document->loadHTML(is_null($html) ? $this->__xhtml : $html); $converter = new CssSelectorConverter(); $xpath = new DOMXPath($document); $elems = $xpath->query($converter->toXPath($select)); return $elems; }
/** * Converts the loaded HTML into an HTML-string with inline styles based on the loaded CSS * * @return string * @param bool [optional] $outputXHTML Should we output valid XHTML? */ public function convert($outputXHTML = false) { // redefine $outputXHTML = (bool) $outputXHTML; // validate if ($this->html == null) { throw new Exception('No HTML provided.'); } // should we use inline style-block if ($this->useInlineStylesBlock) { // init var $matches = array(); // match the style blocks preg_match_all('|<style(.*)>(.*)</style>|isU', $this->html, $matches); // any style-blocks found? if (!empty($matches[2])) { // add foreach ($matches[2] as $match) { $this->css .= trim($match) . "\n"; } } } // process css $cssRules = $this->processCSS(); // create new DOMDocument $document = new \DOMDocument('1.0', $this->getEncoding()); // set error level $internalErrors = libxml_use_internal_errors(true); // load HTML $document->loadHTML($this->html); // Restore error level libxml_use_internal_errors($internalErrors); // create new XPath $xPath = new \DOMXPath($document); // any rules? if (!empty($cssRules)) { // loop rules foreach ($cssRules as $rule) { try { if (class_exists("Symfony\\Component\\CssSelector\\CssSelectorConverter")) { // Symfony >= 2.8 $cssSelector = new CssSelectorConverter(); $query = $cssSelector->toXPath($rule['selector']); } else { // Symfony < 2.8 $query = CssSelector::toXPath($rule['selector']); } } catch (ExceptionInterface $e) { continue; } // search elements $elements = $xPath->query($query); // validate elements if ($elements === false) { continue; } // loop found elements foreach ($elements as $element) { // no styles stored? if ($element->attributes->getNamedItem('data-css-to-inline-styles-original-styles') == null) { // init var $originalStyle = ''; if ($element->attributes->getNamedItem('style') !== null) { $originalStyle = $element->attributes->getNamedItem('style')->value; } // store original styles $element->setAttribute('data-css-to-inline-styles-original-styles', $originalStyle); // clear the styles $element->setAttribute('style', ''); } // init var $properties = array(); // get current styles $stylesAttribute = $element->attributes->getNamedItem('style'); // any styles defined before? if ($stylesAttribute !== null) { // get value for the styles attribute $definedStyles = (string) $stylesAttribute->value; // split into properties $definedProperties = $this->splitIntoProperties($definedStyles); // loop properties foreach ($definedProperties as $property) { // validate property if ($property == '') { continue; } // split into chunks $chunks = (array) explode(':', trim($property), 2); // validate if (!isset($chunks[1])) { continue; } // loop chunks $properties[$chunks[0]] = trim($chunks[1]); } } // add new properties into the list foreach ($rule['properties'] as $key => $value) { // If one of the rules is already set and is !important, don't apply it, // except if the new rule is also important. if (!isset($properties[$key]) || stristr($properties[$key], '!important') === false || stristr(implode('', $value), '!important') !== false) { $properties[$key] = $value; } } // build string $propertyChunks = array(); // build chunks foreach ($properties as $key => $values) { foreach ((array) $values as $value) { $propertyChunks[] = $key . ': ' . $value . ';'; } } // build properties string $propertiesString = implode(' ', $propertyChunks); // set attribute if ($propertiesString != '') { $element->setAttribute('style', $propertiesString); } } } // reapply original styles // search elements $elements = $xPath->query('//*[@data-css-to-inline-styles-original-styles]'); // loop found elements foreach ($elements as $element) { // get the original styles $originalStyle = $element->attributes->getNamedItem('data-css-to-inline-styles-original-styles')->value; if ($originalStyle != '') { $originalProperties = array(); $originalStyles = $this->splitIntoProperties($originalStyle); foreach ($originalStyles as $property) { // validate property if ($property == '') { continue; } // split into chunks $chunks = (array) explode(':', trim($property), 2); // validate if (!isset($chunks[1])) { continue; } // loop chunks $originalProperties[$chunks[0]] = trim($chunks[1]); } // get current styles $stylesAttribute = $element->attributes->getNamedItem('style'); $properties = array(); // any styles defined before? if ($stylesAttribute !== null) { // get value for the styles attribute $definedStyles = (string) $stylesAttribute->value; // split into properties $definedProperties = $this->splitIntoProperties($definedStyles); // loop properties foreach ($definedProperties as $property) { // validate property if ($property == '') { continue; } // split into chunks $chunks = (array) explode(':', trim($property), 2); // validate if (!isset($chunks[1])) { continue; } // loop chunks $properties[$chunks[0]] = trim($chunks[1]); } } // add new properties into the list foreach ($originalProperties as $key => $value) { $properties[$key] = $value; } // build string $propertyChunks = array(); // build chunks foreach ($properties as $key => $values) { foreach ((array) $values as $value) { $propertyChunks[] = $key . ': ' . $value . ';'; } } // build properties string $propertiesString = implode(' ', $propertyChunks); // set attribute if ($propertiesString != '') { $element->setAttribute('style', $propertiesString); } } // remove placeholder $element->removeAttribute('data-css-to-inline-styles-original-styles'); } } // strip original style tags if we need to if ($this->stripOriginalStyleTags) { $this->stripOriginalStyleTags($xPath); } // cleanup the HTML if we need to if ($this->cleanup) { $this->cleanupHTML($xPath); } // should we output XHTML? if ($outputXHTML) { // set formating $document->formatOutput = true; // get the HTML as XML $html = $document->saveXML(null, LIBXML_NOEMPTYTAG); // remove the XML-header $html = ltrim(preg_replace('/<\\?xml (.*)\\?>/', '', $html)); } else { // get the HTML $html = $document->saveHTML(); } // return return $html; }