/** * 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); }
public function testBlender() { $inputDir = __DIR__ . '/../../ressources/input'; $outputDir = __DIR__ . '/../../ressources/output'; $this->process->blend($inputDir, $outputDir); $exiftoolBinary = __DIR__ . '/../../../vendor/alchemy/exiftool/exiftool'; $metas = array('NomdelaPhoto' => array('src' => 'IPTC:Headline', 'value' => 'hello'), 'Rubrique' => array('src' => 'IPTC:Category', 'value' => 'salut'), 'MotsCles' => array('src' => 'IPTC:Keywords', 'value' => 'kakoo'), 'DatedeParution' => array('src' => 'IPTC:Source', 'value' => '2012/04/13'), 'DatePrisedeVue' => array('src' => 'IPTC:DateCreated', 'value' => '2012:04:13'), 'Ville' => array('src' => 'IPTC:City', 'value' => 'paris'), 'Pays' => array('src' => 'IPTC:Country-PrimaryLocationName', 'value' => 'france'), 'Copyright' => array('src' => 'IPTC:CopyrightNotice', 'value' => 'yata')); $cmd = $exiftoolBinary . ' -X ' . __DIR__ . '/../../ressources/output/1.jpg'; $output = shell_exec($cmd); if ($output) { $document = new \DOMDocument(); $document->loadXML($output); $xpath = new \DOMXPath($document); $xPathQuery = CssSelector::toXPath('*'); foreach ($metas as $metaInfo) { $found = false; foreach ($xpath->query($xPathQuery) as $node) { $nodeName = $node->nodeName; $value = $node->nodeValue; if ($nodeName == $metaInfo['src']) { $this->assertEquals($value, $metaInfo['value']); $found = true; continue; } } if (!$found) { $this->fail('missing ' . $metaInfo['src']); } } } }
/** * 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'); } return CSS::toXPath($locator); }
/** * Return DOMNodeList from CSS selector * * @param $string * @return \DOMNodeList */ public function query($string) { CssSelector::disableHtmlExtension(); $xpathQuery = CssSelector::toXPath($string); $xpath = new \DOMXPath($this->data); return $xpath->query($xpathQuery); }
public function testCsstoXPath() { $this->assertEquals('descendant-or-self::h1', CssSelector::toXPath('h1')); $this->assertEquals("descendant-or-self::h1[@id = 'foo']", CssSelector::toXPath('h1#foo')); $this->assertEquals("descendant-or-self::h1[contains(concat(' ', normalize-space(@class), ' '), ' foo ')]", CssSelector::toXPath('h1.foo')); $this->assertEquals('descendant-or-self::foo:h1', CssSelector::toXPath('foo|h1')); }
/** * Create and update XPath expression */ public function updateXPathExpression() { if ($this->type === 'css') { $this->xpath_expression = CssSelector::toXPath($this->selector); } else { $this->xpath_expression = $this->selector; } }
protected function execute(InputInterface $input, OutputInterface $output) { $selector = $input->getArgument('selector'); /** @var FormatterHelper $formatter */ $formatter = $this->getHelper('formatter'); $block = $formatter->formatBlock(CssSelector::toXPath($selector), 'question', true); $output->writeln($block); }
/** * @param $selector * @return bool */ public static function isCSS($selector) { try { CssSelector::toXPath($selector); } catch (ParseException $e) { return false; } return true; }
public function html() { $ref = clone $this->_doc; $xpath = new DOMXPath($ref); foreach ($xpath->query(CssSelector::toXPath('*[data-domref]')) as $node) { $node->removeAttribute('data-domref'); } return $ref->saveHTML(); }
protected static function toXPath($selector) { try { $xpath = CssSelector::toXPath($selector); } catch (\Symfony\Component\CssSelector\Exception\ParseException $e) { $xpath = $selector; } return $xpath; }
/** * Ensures that the rendered results are working as expected. * * @param array $expected * The expected rows of the result. */ protected function assertRows($expected = []) { $actual = []; $rows = $this->cssSelect('div.views-row'); foreach ($rows as $row) { $actual[] = ['title' => (string) $row->xpath(CssSelector::toXPath('.views-field-title span.field-content a'))[0], 'sticky' => (string) $row->xpath(CssSelector::toXPath('.views-field-sticky span.field-content'))[0]]; } $this->assertEqual($actual, $expected); }
public function testParseExceptions() { try { CssSelector::toXPath('h1:'); $this->fail('->parse() throws an Exception if the css selector is not valid'); } catch (\Exception $e) { $this->assertInstanceOf('\\Symfony\\Component\\CssSelector\\Exception\\ParseException', $e, '->parse() throws an Exception if the css selector is not valid'); $this->assertEquals("Expected identifier, but <eof at 3> found.", $e->getMessage(), '->parse() throws an Exception if the css selector is not valid'); } }
/** * Metodo que convierte un selector css en un xpath * @param string $css_selector Cadena de texto con el selector css. * @return string|NULL Devuelve una cadena de texto con formato xpath si la converción e sposible o NULL en caso contrario. */ private function toXPath($css_selector) { $xpath = Null; try { $xpath = $this->selector->toXPath($css_selector); } catch (\Exception $e) { $this->logger->logError('E003', array($css_selector)); $this->logger->logError('E000', array($e->getMessage())); } return $xpath; }
/** * Evaluates the constraint for parameter $other. Returns true if the * constraint is met, false otherwise. * * @param mixed $other * @return bool */ public function matches($other) { if ($other instanceof DOMElement) { $xpathSelector = CssSelector::toXPath($this->cssSelector, '//'); $xpath = new DOMXPath($other->ownerDocument); foreach ($xpath->query($xpathSelector) as $node) { if ($node === $other) { return true; } } } return false; }
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; }
/** * @param $cssOrXPath * @return \DOMElement */ public function matchElement($cssOrXPath) { $xpath = new \DOMXpath($this->xml); try { $selector = CssSelector::toXPath($cssOrXPath); $els = $xpath->query($selector); if ($els) { return $els->item(0); } } catch (ParseException $e) { } $els = $xpath->query($cssOrXPath); if ($els) { return $els->item(0); } throw new ElementNotFound($cssOrXPath); }
/** * Prepares everything and inserts inline styles into html * @param string $html represents html document * @return string */ public function render($html) { $this->dom = new \DOMDocument(); $this->dom->loadHTML($html); $this->finder = new \DOMXPath($this->dom); $this->css = $this->getCSS(); foreach ($this->css->getAllRuleSets() as $ruleSet) { $selector = $ruleSet->getSelector(); foreach ($this->finder->evaluate(CssSelector::toXPath($selector[0])) as $node) { if ($node->getAttribute('style')) { $node->setAttribute('style', $node->getAttribute('style') . implode(' ', $ruleSet->getRules())); } else { $node->setAttribute('style', implode(' ', $ruleSet->getRules())); } } } return $this->dom->saveHTML(); }
/** * Build a Table Of Content * * @static * @param string $html html string * @return array */ public static function buildTOC($html) { if (!$html) { return array(); } $html = static::addHeadingsId($html, 'h1, h2, h3, h4, h5, h6'); $document = new \DOMDocument(); $document->loadHTML('<?xml encoding="UTF-8">' . $html); $xpath = new \DOMXPath($document); $toc = array(); $h1 = $h2 = $h3 = $h4 = $h5 = $h5 = $h6 = 0; foreach ($xpath->query(CssSelector::toXPath('h1, h2, h3, h4, h5, h6')) as $node) { $nodeName = $node->nodeName; $title = $node->nodeValue; $id = $node->getAttribute('id'); switch ($nodeName) { case 'h1': $toc[++$h1] = array('title' => $title, 'id' => $id, 'children' => array()); break; case 'h2': $toc = self::fixToc($toc, $nodeName, $h1, $h2, $h3, $h4, $h5, $h5); $toc[$h1]['children'][++$h2] = array('title' => $title, 'id' => $id, 'children' => array()); break; case 'h3': $toc = self::fixToc($toc, $nodeName, $h1, $h2, $h3, $h4, $h5, $h5); $toc[$h1]['children'][$h2]['children'][++$h3] = array('title' => $title, 'id' => $id, 'children' => array()); break; case 'h4': $toc = self::fixToc($toc, $nodeName, $h1, $h2, $h3, $h4, $h5, $h5); $toc[$h1]['children'][$h2]['children'][$h3]['children'][++$h4] = array('title' => $title, 'id' => $id, 'children' => array()); break; case 'h5': $toc = self::fixToc($toc, $nodeName, $h1, $h2, $h3, $h4, $h5, $h5); $toc[$h1]['children'][$h2]['children'][$h3]['children'][$h4]['children'][++$h5] = array('title' => $title, 'id' => $id, 'children' => array()); break; case 'h6': $toc = self::fixToc($toc, $nodeName, $h1, $h2, $h3, $h4, $h5, $h5); $toc[$h1]['children'][$h2]['children'][$h3]['children'][$h4]['children'][$h5]['children'][++$h6] = array('title' => $title, 'id' => $id, 'children' => array()); break; } } return $toc; }
protected function execute(InputInterface $input, OutputInterface $output) { /** @var FormatterHelper $formatter */ $formatter = $this->getHelper('formatter'); $html = file_get_contents('http://spb.hh.ru/search/vacancy?text=php&clusters=true&enable_snippets=true'); $crawler = new Crawler($html, 'http://spb.hh.ru/search/vacancy?text=php&clusters=true&enable_snippets=true'); $output->writeln($formatter->formatBlock('Vacancies', 'question', true)); $crawler->filterXPath(CssSelector::toXPath('body a.search-result-item__name'))->each(function (Crawler $node) use($output) { $output->writeln(sprintf('<comment>%s</comment>', $node->text())); }); $data = $crawler->filter('body a.search-result-item__name')->extract(['_text', 'class']); print_r($data[0]); $output->writeln($formatter->formatBlock('Link test', 'question', true)); $link = $crawler->selectLink('PHP developer')->link(); $output->writeln($link->getUri()); $crawler = new Crawler(file_get_contents('http://spb.hh.ru/login'), 'http://spb.hh.ru/login'); $output->writeln($formatter->formatBlock('Form test', 'question', true)); $form = $crawler->selectButton('Войти')->form(['username' => 'name', 'password' => 'pass']); $output->writeln($form->getUri()); $form['remember']->tick(); $output->writeln(print_r($form->getPhpValues())); }
/** * @param $selector * * @return Crawler */ protected function match($selector) { if (is_array($selector)) { return $this->strictMatch($selector); } try { $selector = CssSelector::toXPath($selector); } catch (ParseException $e) { } if (!Locator::isXPath($selector)) { return null; } return @$this->crawler->filterXPath($selector); }
/** * 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 * * @api */ public function filter($selector) { if (!class_exists('Symfony\\Component\\CssSelector\\CssSelector')) { // @codeCoverageIgnoreStart throw new \RuntimeException('Unable to filter with a CSS selector as the Symfony CssSelector is not installed (you can use filterXPath instead).'); // @codeCoverageIgnoreEnd } return $this->filterXPath(CssSelector::toXPath($selector)); }
/** * @param $selector * * @return Crawler */ protected function match($selector) { if (is_array($selector)) { return $this->strictMatch($selector); } try { $selector = CssSelector::toXPath($selector); } catch (ParseException $e) { } if (!Locator::isXPath($selector)) { codecept_debug("XPath `{$selector}` is malformed!"); return new \Symfony\Component\DomCrawler\Crawler(); } return @$this->crawler->filterXPath($selector); }
/** * Constructor. * * @param String $css */ public function __construct($css) { $this->xpath = CssSelector::toXPath($css); }
/** * Searches elements using a CSS selector in the raw content. * * The search is relative to the root element (HTML tag normally) of the page. * * @param string $selector * CSS selector to use in the search. * * @return \SimpleXMLElement[] * The return value of the XPath search performed after converting the CSS * selector to an XPath selector. */ protected function cssSelect($selector) { return $this->xpath(CssSelector::toXPath($selector)); }
/** * @param $content string * * @return string */ private function removeLastItem($content) { $document = new \DOMDocument('1.0', \Yii::$app->charset); $crawler = new Crawler(); $crawler->addHTMLContent($content, \Yii::$app->charset); $root = $document->appendChild($document->createElement('_root')); $crawler->rewind(); $root->appendChild($document->importNode($crawler->current(), true)); $domxpath = new \DOMXPath($document); $crawlerInverse = $domxpath->query(CssSelector::toXPath($this->widgetItem . ':last-child')); foreach ($crawlerInverse as $key => $elementToRemove) { $parent = $elementToRemove->parentNode; $parent->removeChild($elementToRemove); } $crawler->clear(); $crawler->add($document); return $crawler->filter('body')->eq(0)->html(); }
/** * 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\\CssSelector')) { throw new \RuntimeException('Unable to filter with a CSS selector as the Symfony CssSelector is not installed (you can use filterXPath instead).'); } // The CssSelector already prefixes the selector with descendant-or-self:: return $this->filterRelativeXPath(CssSelector::toXPath($selector)); }
/** * 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 $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($this->cssRules)) { // loop rules foreach ($this->cssRules as $rule) { try { $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); } // 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(); } // cleanup the HTML if we need to if ($this->cleanup) { $html = $this->cleanupHTML($html); } // return return $html; }
/** * @param string $selector */ public function __construct($selector) { $this->xPath = CssSelector::toXPath($selector, 'descendant::'); }
/** * Translates CSS into XPath. * * @param string $locator current selector locator * * @return string */ public function translateToXPath($locator) { return CSS::toXPath($locator); }
public function testGetFeed() { $feed = self::$DI['app']['EM']->find('Phraseanet:Feed', 1); $feeds = self::$DI['app']['EM']->getRepository('Phraseanet:Feed')->getAllForUser(self::$DI['app']['acl']->get(self::$DI['user'])); $crawler = self::$DI['client']->request('GET', '/prod/feeds/feed/' . $feed->getId() . "/"); foreach ($feeds as $one_feed) { $path = CssSelector::toXPath("ul.submenu a[href='/prod/feeds/feed/" . $one_feed->getId() . "/']"); $msg = sprintf("user %s has access to feed %s", self::$DI['user']->getId(), $one_feed->getId()); if ($one_feed->hasAccess(self::$DI['user'], self::$DI['app'])) { $this->assertEquals(1, $crawler->filterXPath($path)->count(), $msg); } else { $this->fail('FeedRepository::getAllForUser should return feeds I am allowed to access'); } } }