XPathExpr.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <?php
  2. namespace Symfony\Component\CssSelector;
  3. /*
  4. * This file is part of the Symfony package.
  5. *
  6. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. /**
  12. * XPathExpr represents an XPath expression.
  13. *
  14. * This component is a port of the Python lxml library,
  15. * which is copyright Infrae and distributed under the BSD license.
  16. *
  17. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  18. */
  19. class XPathExpr
  20. {
  21. protected $prefix;
  22. protected $path;
  23. protected $element;
  24. protected $condition;
  25. protected $starPrefix;
  26. public function __construct($prefix = null, $path = null, $element = '*', $condition = null, $starPrefix = false)
  27. {
  28. $this->prefix = $prefix;
  29. $this->path = $path;
  30. $this->element = $element;
  31. $this->condition = $condition;
  32. $this->starPrefix = $starPrefix;
  33. }
  34. public function getPrefix()
  35. {
  36. return $this->prefix;
  37. }
  38. public function getPath()
  39. {
  40. return $this->path;
  41. }
  42. public function hasStarPrefix()
  43. {
  44. return $this->starPrefix;
  45. }
  46. public function getElement()
  47. {
  48. return $this->element;
  49. }
  50. public function getCondition()
  51. {
  52. return $this->condition;
  53. }
  54. public function __toString()
  55. {
  56. $path = '';
  57. if (null !== $this->prefix) {
  58. $path .= $this->prefix;
  59. }
  60. if (null !== $this->path) {
  61. $path .= $this->path;
  62. }
  63. $path .= $this->element;
  64. if ($this->condition) {
  65. $path .= sprintf('[%s]', $this->condition);
  66. }
  67. return $path;
  68. }
  69. public function addCondition($condition)
  70. {
  71. if ($this->condition) {
  72. $this->condition = sprintf('%s and (%s)', $this->condition, $condition);
  73. } else {
  74. $this->condition = $condition;
  75. }
  76. }
  77. public function addPrefix($prefix)
  78. {
  79. if ($this->prefix) {
  80. $this->prefix = $prefix.$this->prefix;
  81. } else {
  82. $this->prefix = $prefix;
  83. }
  84. }
  85. public function addNameTest()
  86. {
  87. if ($this->element == '*') {
  88. // We weren't doing a test anyway
  89. return;
  90. }
  91. $this->addCondition(sprintf('name() = %s', XPathExpr::xpathLiteral($this->element)));
  92. $this->element = '*';
  93. }
  94. public function addStarPrefix()
  95. {
  96. /*
  97. Adds a /* prefix if there is no prefix. This is when you need
  98. to keep context's constrained to a single parent.
  99. */
  100. if ($this->path) {
  101. $this->path .= '*/';
  102. } else {
  103. $this->path = '*/';
  104. }
  105. $this->starPrefix = true;
  106. }
  107. public function join($combiner, $other)
  108. {
  109. $prefix = (string) $this;
  110. $prefix .= $combiner;
  111. $path = $other->getPrefix().$other->getPath();
  112. /* We don't need a star prefix if we are joining to this other
  113. prefix; so we'll get rid of it */
  114. if ($other->hasStarPrefix() && $path == '*/') {
  115. $path = '';
  116. }
  117. $this->prefix = $prefix;
  118. $this->path = $path;
  119. $this->element = $other->getElement();
  120. $this->condition = $other->GetCondition();
  121. }
  122. static public function xpathLiteral($s)
  123. {
  124. if ($s instanceof Node\ElementNode) {
  125. // This is probably a symbol that looks like an expression...
  126. $s = $s->formatElement();
  127. } else {
  128. $s = (string) $s;
  129. }
  130. if (false === strpos($s, "'")) {
  131. return sprintf("'%s'", $s);
  132. }
  133. if (false === strpos($s, '"')) {
  134. return sprintf('"%s"', $s);
  135. }
  136. $string = $s;
  137. $parts = array();
  138. while (true) {
  139. if (false !== $pos = strpos($string, "'")) {
  140. $parts[] = sprintf("'%s'", substr($string, 0, $pos));
  141. $parts[] = "\"'\"";
  142. $string = substr($string, $pos + 1);
  143. } else {
  144. $parts[] = "'$string'";
  145. break;
  146. }
  147. }
  148. return sprintf('concat(%s)', implode($parts, ', '));
  149. }
  150. }