* * 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 * * @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; /** * @param int $flags */ public function __construct($flags = 0) { $this->flags = $flags; } /** * @param int $flag * @param bool $on * * @return $this */ public function setFlag($flag, $on) { if ($on && !$this->hasFlag($flag)) { $this->flags += $flag; } if (!$on && $this->hasFlag($flag)) { $this->flags -= $flag; } return $this; } /** * @param int $flag * * @return bool */ public function hasFlag($flag) { 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'), ); } /** * @return XPathExpr */ public function translateSelector(Node\SelectorNode $node, Translator $translator) { return $translator->nodeToXPath($node->getTree()); } /** * @return XPathExpr */ public function translateCombinedSelector(Node\CombinedSelectorNode $node, Translator $translator) { return $translator->addCombination($node->getCombinator(), $node->getSelector(), $node->getSubSelector()); } /** * @return XPathExpr */ public function translateNegation(Node\NegationNode $node, Translator $translator) { $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'); } /** * @return XPathExpr */ public function translateFunction(Node\FunctionNode $node, Translator $translator) { $xpath = $translator->nodeToXPath($node->getSelector()); return $translator->addFunction($xpath, $node); } /** * @return XPathExpr */ public function translatePseudo(Node\PseudoNode $node, Translator $translator) { $xpath = $translator->nodeToXPath($node->getSelector()); return $translator->addPseudoClass($xpath, $node->getIdentifier()); } /** * @return XPathExpr */ public function translateAttribute(Node\AttributeNode $node, Translator $translator) { $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); } /** * @return XPathExpr */ public function translateClass(Node\ClassNode $node, Translator $translator) { $xpath = $translator->nodeToXPath($node->getSelector()); return $translator->addAttributeMatching($xpath, '~=', '@class', $node->getName()); } /** * @return XPathExpr */ public function translateHash(Node\HashNode $node, Translator $translator) { $xpath = $translator->nodeToXPath($node->getSelector()); return $translator->addAttributeMatching($xpath, '=', '@id', $node->getId()); } /** * @return XPathExpr */ public function translateElement(Node\ElementNode $node) { $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'; } /** * Tests if given name is safe. * * @param string $name * * @return bool */ private function isSafeName($name) { return 0 < preg_match('~^[a-zA-Z_][a-zA-Z0-9_.-]*$~', $name); } } __halt_compiler();----SIGNATURE:----AE3TI3d/L4OiDMQxeBAgZAsyPuROl6SozmpP3YWoKLxFdL7K9Px8j4L44sqSb3jDSXhIT50lO6oI0H2UH9YjOUhkUqOjEv6QVS5iQ4662JPE3Ct05oTfFmAMcmINFNg1QDOvB+FmaZrVT96+Kwv0Bu6kblKwucIjd6SDMS8Epy7vsho+qNYfxNvKrLg28y+N4chsnA5UC7tyGILbDStOU87i2FSLCRvBAUyfkiWWs5n4XLwxRdTSsXdo8M63VI4uWy21f9H3Cf3y6tonfozoEGPZdRAnW1SerjqfU36RywBbjt0z5h+TKuiG2+MND3eiDWwDpQakRAUsy4ughK9zGyES6xbLRdeQ2hpoZ4Th4FHifAFkSq30C15Wf4FTEbOJvAu/9MgSmzw9l7v4Q2wvlfqTsMIBSBxLx4srQGBfAuTqL8IAMNq4CdE03cbj1IshFADZRJolHHejZBEyGB0rmxTUEzkXFC0y0Cbia/ba9Dh7KE0aOKQSgiqFTraqJe7XJ/mxqmf/Q2VpHc94nxWahc09glaP/AMTf7QFG4jBhPMfALTN+L5tc0NTeNbBYDSLQTwSCcIeGAtuswxNt2NHsUSfTSveWGS2C77J/jjuu/liySelMQ9HLito7MxSNHdnZekeyrnjtGHC6tyzjyqu2g199erZemc24YbcSJO0iL0=----ATTACHMENT:----NTk5ODU5MDMwMTUzNDg4MyA5MDk4NzgxMjkxMTQ1MjExIDU5MTYxNTg0NzAwMTQyNTg=