123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- <?php
- /*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
- namespace Symfony\Component\CssSelector\XPath\Extension;
- use Symfony\Component\CssSelector\Exception\ExpressionErrorException;
- use Symfony\Component\CssSelector\Node\FunctionNode;
- use Symfony\Component\CssSelector\XPath\Translator;
- use Symfony\Component\CssSelector\XPath\XPathExpr;
- /**
- * XPath expression translator HTML extension.
- *
- * This component is a port of the Python cssselect library,
- * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
- *
- * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
- *
- * @internal
- */
- class HtmlExtension extends AbstractExtension
- {
- /**
- * Constructor.
- *
- * @param Translator $translator
- */
- public function __construct(Translator $translator)
- {
- $translator
- ->getExtension('node')
- ->setFlag(NodeExtension::ELEMENT_NAME_IN_LOWER_CASE, true)
- ->setFlag(NodeExtension::ATTRIBUTE_NAME_IN_LOWER_CASE, true);
- }
- /**
- * {@inheritdoc}
- */
- public function getPseudoClassTranslators()
- {
- return array(
- 'checked' => array($this, 'translateChecked'),
- 'link' => array($this, 'translateLink'),
- 'disabled' => array($this, 'translateDisabled'),
- 'enabled' => array($this, 'translateEnabled'),
- 'selected' => array($this, 'translateSelected'),
- 'invalid' => array($this, 'translateInvalid'),
- 'hover' => array($this, 'translateHover'),
- 'visited' => array($this, 'translateVisited'),
- );
- }
- /**
- * {@inheritdoc}
- */
- public function getFunctionTranslators()
- {
- return array(
- 'lang' => array($this, 'translateLang'),
- );
- }
- /**
- * @param XPathExpr $xpath
- *
- * @return XPathExpr
- */
- public function translateChecked(XPathExpr $xpath)
- {
- return $xpath->addCondition(
- '(@checked '
- ."and (name(.) = 'input' or name(.) = 'command')"
- ."and (@type = 'checkbox' or @type = 'radio'))"
- );
- }
- /**
- * @param XPathExpr $xpath
- *
- * @return XPathExpr
- */
- public function translateLink(XPathExpr $xpath)
- {
- return $xpath->addCondition("@href and (name(.) = 'a' or name(.) = 'link' or name(.) = 'area')");
- }
- /**
- * @param XPathExpr $xpath
- *
- * @return XPathExpr
- */
- public function translateDisabled(XPathExpr $xpath)
- {
- return $xpath->addCondition(
- '('
- .'@disabled and'
- .'('
- ."(name(.) = 'input' and @type != 'hidden')"
- ." or name(.) = 'button'"
- ." or name(.) = 'select'"
- ." or name(.) = 'textarea'"
- ." or name(.) = 'command'"
- ." or name(.) = 'fieldset'"
- ." or name(.) = 'optgroup'"
- ." or name(.) = 'option'"
- .')'
- .') or ('
- ."(name(.) = 'input' and @type != 'hidden')"
- ." or name(.) = 'button'"
- ." or name(.) = 'select'"
- ." or name(.) = 'textarea'"
- .')'
- .' and ancestor::fieldset[@disabled]'
- );
- // todo: in the second half, add "and is not a descendant of that fieldset element's first legend element child, if any."
- }
- /**
- * @param XPathExpr $xpath
- *
- * @return XPathExpr
- */
- public function translateEnabled(XPathExpr $xpath)
- {
- return $xpath->addCondition(
- '('
- .'@href and ('
- ."name(.) = 'a'"
- ." or name(.) = 'link'"
- ." or name(.) = 'area'"
- .')'
- .') or ('
- .'('
- ."name(.) = 'command'"
- ." or name(.) = 'fieldset'"
- ." or name(.) = 'optgroup'"
- .')'
- .' and not(@disabled)'
- .') or ('
- .'('
- ."(name(.) = 'input' and @type != 'hidden')"
- ." or name(.) = 'button'"
- ." or name(.) = 'select'"
- ." or name(.) = 'textarea'"
- ." or name(.) = 'keygen'"
- .')'
- .' and not (@disabled or ancestor::fieldset[@disabled])'
- .') or ('
- ."name(.) = 'option' and not("
- .'@disabled or ancestor::optgroup[@disabled]'
- .')'
- .')'
- );
- }
- /**
- * @param XPathExpr $xpath
- * @param FunctionNode $function
- *
- * @return XPathExpr
- *
- * @throws ExpressionErrorException
- */
- public function translateLang(XPathExpr $xpath, FunctionNode $function)
- {
- $arguments = $function->getArguments();
- foreach ($arguments as $token) {
- if (!($token->isString() || $token->isIdentifier())) {
- throw new ExpressionErrorException(
- 'Expected a single string or identifier for :lang(), got '
- .implode(', ', $arguments)
- );
- }
- }
- return $xpath->addCondition(sprintf(
- 'ancestor-or-self::*[@lang][1][starts-with(concat('
- ."translate(@%s, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '-')"
- .', %s)]',
- 'lang',
- Translator::getXpathLiteral(strtolower($arguments[0]->getValue()).'-')
- ));
- }
- /**
- * @param XPathExpr $xpath
- *
- * @return XPathExpr
- */
- public function translateSelected(XPathExpr $xpath)
- {
- return $xpath->addCondition("(@selected and name(.) = 'option')");
- }
- /**
- * @param XPathExpr $xpath
- *
- * @return XPathExpr
- */
- public function translateInvalid(XPathExpr $xpath)
- {
- return $xpath->addCondition('0');
- }
- /**
- * @param XPathExpr $xpath
- *
- * @return XPathExpr
- */
- public function translateHover(XPathExpr $xpath)
- {
- return $xpath->addCondition('0');
- }
- /**
- * @param XPathExpr $xpath
- *
- * @return XPathExpr
- */
- public function translateVisited(XPathExpr $xpath)
- {
- return $xpath->addCondition('0');
- }
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'html';
- }
- }
|