radarrplexorganizrnginxsonarrdashboardserverhomepagesabnzbdheimdallembycouchpotatonzbgetbookmarkapplication-dashboardmuximuxlandingpagestartpagelandinghtpc
		
		
		
		
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							197 lines
						
					
					
						
							5.7 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							197 lines
						
					
					
						
							5.7 KiB
						
					
					
				
								<?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\Node;
							 | 
						|
								use Symfony\Component\CssSelector\XPath\Translator;
							 | 
						|
								use Symfony\Component\CssSelector\XPath\XPathExpr;
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * XPath expression translator node 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 NodeExtension extends AbstractExtension
							 | 
						|
								{
							 | 
						|
								    const ELEMENT_NAME_IN_LOWER_CASE = 1;
							 | 
						|
								    const ATTRIBUTE_NAME_IN_LOWER_CASE = 2;
							 | 
						|
								    const ATTRIBUTE_VALUE_IN_LOWER_CASE = 4;
							 | 
						|
								
							 | 
						|
								    private $flags;
							 | 
						|
								
							 | 
						|
								    public function __construct(int $flags = 0)
							 | 
						|
								    {
							 | 
						|
								        $this->flags = $flags;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * @return $this
							 | 
						|
								     */
							 | 
						|
								    public function setFlag(int $flag, bool $on)
							 | 
						|
								    {
							 | 
						|
								        if ($on && !$this->hasFlag($flag)) {
							 | 
						|
								            $this->flags += $flag;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if (!$on && $this->hasFlag($flag)) {
							 | 
						|
								            $this->flags -= $flag;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return $this;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    public function hasFlag(int $flag): bool
							 | 
						|
								    {
							 | 
						|
								        return (bool) ($this->flags & $flag);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * {@inheritdoc}
							 | 
						|
								     */
							 | 
						|
								    public function getNodeTranslators()
							 | 
						|
								    {
							 | 
						|
								        return array(
							 | 
						|
								            'Selector' => array($this, 'translateSelector'),
							 | 
						|
								            'CombinedSelector' => array($this, 'translateCombinedSelector'),
							 | 
						|
								            'Negation' => array($this, 'translateNegation'),
							 | 
						|
								            'Function' => array($this, 'translateFunction'),
							 | 
						|
								            'Pseudo' => array($this, 'translatePseudo'),
							 | 
						|
								            'Attribute' => array($this, 'translateAttribute'),
							 | 
						|
								            'Class' => array($this, 'translateClass'),
							 | 
						|
								            'Hash' => array($this, 'translateHash'),
							 | 
						|
								            'Element' => array($this, 'translateElement'),
							 | 
						|
								        );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    public function translateSelector(Node\SelectorNode $node, Translator $translator): XPathExpr
							 | 
						|
								    {
							 | 
						|
								        return $translator->nodeToXPath($node->getTree());
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    public function translateCombinedSelector(Node\CombinedSelectorNode $node, Translator $translator): XPathExpr
							 | 
						|
								    {
							 | 
						|
								        return $translator->addCombination($node->getCombinator(), $node->getSelector(), $node->getSubSelector());
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    public function translateNegation(Node\NegationNode $node, Translator $translator): XPathExpr
							 | 
						|
								    {
							 | 
						|
								        $xpath = $translator->nodeToXPath($node->getSelector());
							 | 
						|
								        $subXpath = $translator->nodeToXPath($node->getSubSelector());
							 | 
						|
								        $subXpath->addNameTest();
							 | 
						|
								
							 | 
						|
								        if ($subXpath->getCondition()) {
							 | 
						|
								            return $xpath->addCondition(sprintf('not(%s)', $subXpath->getCondition()));
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return $xpath->addCondition('0');
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    public function translateFunction(Node\FunctionNode $node, Translator $translator): XPathExpr
							 | 
						|
								    {
							 | 
						|
								        $xpath = $translator->nodeToXPath($node->getSelector());
							 | 
						|
								
							 | 
						|
								        return $translator->addFunction($xpath, $node);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    public function translatePseudo(Node\PseudoNode $node, Translator $translator): XPathExpr
							 | 
						|
								    {
							 | 
						|
								        $xpath = $translator->nodeToXPath($node->getSelector());
							 | 
						|
								
							 | 
						|
								        return $translator->addPseudoClass($xpath, $node->getIdentifier());
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    public function translateAttribute(Node\AttributeNode $node, Translator $translator): XPathExpr
							 | 
						|
								    {
							 | 
						|
								        $name = $node->getAttribute();
							 | 
						|
								        $safe = $this->isSafeName($name);
							 | 
						|
								
							 | 
						|
								        if ($this->hasFlag(self::ATTRIBUTE_NAME_IN_LOWER_CASE)) {
							 | 
						|
								            $name = strtolower($name);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if ($node->getNamespace()) {
							 | 
						|
								            $name = sprintf('%s:%s', $node->getNamespace(), $name);
							 | 
						|
								            $safe = $safe && $this->isSafeName($node->getNamespace());
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        $attribute = $safe ? '@'.$name : sprintf('attribute::*[name() = %s]', Translator::getXpathLiteral($name));
							 | 
						|
								        $value = $node->getValue();
							 | 
						|
								        $xpath = $translator->nodeToXPath($node->getSelector());
							 | 
						|
								
							 | 
						|
								        if ($this->hasFlag(self::ATTRIBUTE_VALUE_IN_LOWER_CASE)) {
							 | 
						|
								            $value = strtolower($value);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return $translator->addAttributeMatching($xpath, $node->getOperator(), $attribute, $value);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    public function translateClass(Node\ClassNode $node, Translator $translator): XPathExpr
							 | 
						|
								    {
							 | 
						|
								        $xpath = $translator->nodeToXPath($node->getSelector());
							 | 
						|
								
							 | 
						|
								        return $translator->addAttributeMatching($xpath, '~=', '@class', $node->getName());
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    public function translateHash(Node\HashNode $node, Translator $translator): XPathExpr
							 | 
						|
								    {
							 | 
						|
								        $xpath = $translator->nodeToXPath($node->getSelector());
							 | 
						|
								
							 | 
						|
								        return $translator->addAttributeMatching($xpath, '=', '@id', $node->getId());
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    public function translateElement(Node\ElementNode $node): XPathExpr
							 | 
						|
								    {
							 | 
						|
								        $element = $node->getElement();
							 | 
						|
								
							 | 
						|
								        if ($this->hasFlag(self::ELEMENT_NAME_IN_LOWER_CASE)) {
							 | 
						|
								            $element = strtolower($element);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if ($element) {
							 | 
						|
								            $safe = $this->isSafeName($element);
							 | 
						|
								        } else {
							 | 
						|
								            $element = '*';
							 | 
						|
								            $safe = true;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if ($node->getNamespace()) {
							 | 
						|
								            $element = sprintf('%s:%s', $node->getNamespace(), $element);
							 | 
						|
								            $safe = $safe && $this->isSafeName($node->getNamespace());
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        $xpath = new XPathExpr('', $element);
							 | 
						|
								
							 | 
						|
								        if (!$safe) {
							 | 
						|
								            $xpath->addNameTest();
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return $xpath;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * {@inheritdoc}
							 | 
						|
								     */
							 | 
						|
								    public function getName()
							 | 
						|
								    {
							 | 
						|
								        return 'node';
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    private function isSafeName(string $name): bool
							 | 
						|
								    {
							 | 
						|
								        return 0 < preg_match('~^[a-zA-Z_][a-zA-Z0-9_.-]*$~', $name);
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 |