PseudoClassExtension.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\CssSelector\XPath\Extension;
  11. use Symfony\Component\CssSelector\Exception\ExpressionErrorException;
  12. use Symfony\Component\CssSelector\XPath\XPathExpr;
  13. /**
  14. * XPath expression translator pseudo-class extension.
  15. *
  16. * This component is a port of the Python cssselect library,
  17. * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
  18. *
  19. * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
  20. *
  21. * @internal
  22. */
  23. class PseudoClassExtension extends AbstractExtension
  24. {
  25. /**
  26. * {@inheritdoc}
  27. */
  28. public function getPseudoClassTranslators()
  29. {
  30. return array(
  31. 'root' => array($this, 'translateRoot'),
  32. 'first-child' => array($this, 'translateFirstChild'),
  33. 'last-child' => array($this, 'translateLastChild'),
  34. 'first-of-type' => array($this, 'translateFirstOfType'),
  35. 'last-of-type' => array($this, 'translateLastOfType'),
  36. 'only-child' => array($this, 'translateOnlyChild'),
  37. 'only-of-type' => array($this, 'translateOnlyOfType'),
  38. 'empty' => array($this, 'translateEmpty'),
  39. );
  40. }
  41. /**
  42. * @param XPathExpr $xpath
  43. *
  44. * @return XPathExpr
  45. */
  46. public function translateRoot(XPathExpr $xpath)
  47. {
  48. return $xpath->addCondition('not(parent::*)');
  49. }
  50. /**
  51. * @param XPathExpr $xpath
  52. *
  53. * @return XPathExpr
  54. */
  55. public function translateFirstChild(XPathExpr $xpath)
  56. {
  57. return $xpath
  58. ->addStarPrefix()
  59. ->addNameTest()
  60. ->addCondition('position() = 1');
  61. }
  62. /**
  63. * @param XPathExpr $xpath
  64. *
  65. * @return XPathExpr
  66. */
  67. public function translateLastChild(XPathExpr $xpath)
  68. {
  69. return $xpath
  70. ->addStarPrefix()
  71. ->addNameTest()
  72. ->addCondition('position() = last()');
  73. }
  74. /**
  75. * @param XPathExpr $xpath
  76. *
  77. * @return XPathExpr
  78. *
  79. * @throws ExpressionErrorException
  80. */
  81. public function translateFirstOfType(XPathExpr $xpath)
  82. {
  83. if ('*' === $xpath->getElement()) {
  84. throw new ExpressionErrorException('"*:first-of-type" is not implemented.');
  85. }
  86. return $xpath
  87. ->addStarPrefix()
  88. ->addCondition('position() = 1');
  89. }
  90. /**
  91. * @param XPathExpr $xpath
  92. *
  93. * @return XPathExpr
  94. *
  95. * @throws ExpressionErrorException
  96. */
  97. public function translateLastOfType(XPathExpr $xpath)
  98. {
  99. if ('*' === $xpath->getElement()) {
  100. throw new ExpressionErrorException('"*:last-of-type" is not implemented.');
  101. }
  102. return $xpath
  103. ->addStarPrefix()
  104. ->addCondition('position() = last()');
  105. }
  106. /**
  107. * @param XPathExpr $xpath
  108. *
  109. * @return XPathExpr
  110. */
  111. public function translateOnlyChild(XPathExpr $xpath)
  112. {
  113. return $xpath
  114. ->addStarPrefix()
  115. ->addNameTest()
  116. ->addCondition('last() = 1');
  117. }
  118. /**
  119. * @param XPathExpr $xpath
  120. *
  121. * @return XPathExpr
  122. *
  123. * @throws ExpressionErrorException
  124. */
  125. public function translateOnlyOfType(XPathExpr $xpath)
  126. {
  127. if ('*' === $xpath->getElement()) {
  128. throw new ExpressionErrorException('"*:only-of-type" is not implemented.');
  129. }
  130. return $xpath->addCondition('last() = 1');
  131. }
  132. /**
  133. * @param XPathExpr $xpath
  134. *
  135. * @return XPathExpr
  136. */
  137. public function translateEmpty(XPathExpr $xpath)
  138. {
  139. return $xpath->addCondition('not(*) and not(string-length())');
  140. }
  141. /**
  142. * {@inheritdoc}
  143. */
  144. public function getName()
  145. {
  146. return 'pseudo-class';
  147. }
  148. }