| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 | <?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{    public function __construct(Translator $translator)    {        $translator            ->getExtension('node')            ->setFlag(NodeExtension::ELEMENT_NAME_IN_LOWER_CASE, true)            ->setFlag(NodeExtension::ATTRIBUTE_NAME_IN_LOWER_CASE, true);    }    public function getPseudoClassTranslators(): array    {        return [            'checked' => $this->translateChecked(...),            'link' => $this->translateLink(...),            'disabled' => $this->translateDisabled(...),            'enabled' => $this->translateEnabled(...),            'selected' => $this->translateSelected(...),            'invalid' => $this->translateInvalid(...),            'hover' => $this->translateHover(...),            'visited' => $this->translateVisited(...),        ];    }    public function getFunctionTranslators(): array    {        return [            'lang' => $this->translateLang(...),        ];    }    public function translateChecked(XPathExpr $xpath): XPathExpr    {        return $xpath->addCondition(            '(@checked '            ."and (name(.) = 'input' or name(.) = 'command')"            ."and (@type = 'checkbox' or @type = 'radio'))"        );    }    public function translateLink(XPathExpr $xpath): XPathExpr    {        return $xpath->addCondition("@href and (name(.) = 'a' or name(.) = 'link' or name(.) = 'area')");    }    public function translateDisabled(XPathExpr $xpath): XPathExpr    {        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."    }    public function translateEnabled(XPathExpr $xpath): XPathExpr    {        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]'                .')'            .')'        );    }    /**     * @throws ExpressionErrorException     */    public function translateLang(XPathExpr $xpath, FunctionNode $function): XPathExpr    {        $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()).'-')        ));    }    public function translateSelected(XPathExpr $xpath): XPathExpr    {        return $xpath->addCondition("(@selected and name(.) = 'option')");    }    public function translateInvalid(XPathExpr $xpath): XPathExpr    {        return $xpath->addCondition('0');    }    public function translateHover(XPathExpr $xpath): XPathExpr    {        return $xpath->addCondition('0');    }    public function translateVisited(XPathExpr $xpath): XPathExpr    {        return $xpath->addCondition('0');    }    public function getName(): string    {        return 'html';    }}
 |