You are here

private function Crawler::relativize in Zircon Profile 8

Same name and namespace in other branches
  1. 8.0 vendor/symfony/dom-crawler/Crawler.php \Symfony\Component\DomCrawler\Crawler::relativize()

Make the XPath relative to the current context.

The returned XPath will match elements matching the XPath inside the current crawler when running in the context of a node of the crawler.

Parameters

string $xpath:

Return value

string

1 call to Crawler::relativize()
Crawler::filterXPath in vendor/symfony/dom-crawler/Crawler.php
Filters the list of nodes with an XPath expression.

File

vendor/symfony/dom-crawler/Crawler.php, line 852

Class

Crawler
Crawler eases navigation of a list of \DOMElement objects.

Namespace

Symfony\Component\DomCrawler

Code

private function relativize($xpath) {
  $expressions = array();
  $unionPattern = '/\\|(?![^\\[]*\\])/';

  // An expression which will never match to replace expressions which cannot match in the crawler
  // We cannot simply drop
  $nonMatchingExpression = 'a[name() = "b"]';

  // Split any unions into individual expressions.
  foreach (preg_split($unionPattern, $xpath) as $expression) {
    $expression = trim($expression);
    $parenthesis = '';

    // If the union is inside some braces, we need to preserve the opening braces and apply
    // the change only inside it.
    if (preg_match('/^[\\(\\s*]+/', $expression, $matches)) {
      $parenthesis = $matches[0];
      $expression = substr($expression, strlen($parenthesis));
    }

    // BC for Symfony 2.4 and lower were elements were adding in a fake _root parent
    if (0 === strpos($expression, '/_root/')) {
      $expression = './' . substr($expression, 7);
    }
    elseif (0 === strpos($expression, 'self::*/')) {
      $expression = './' . substr($expression, 8);
    }

    // add prefix before absolute element selector
    if (empty($expression)) {
      $expression = $nonMatchingExpression;
    }
    elseif (0 === strpos($expression, '//')) {
      $expression = 'descendant-or-self::' . substr($expression, 2);
    }
    elseif (0 === strpos($expression, './/')) {
      $expression = 'descendant-or-self::' . substr($expression, 3);
    }
    elseif (0 === strpos($expression, './')) {
      $expression = 'self::' . substr($expression, 2);
    }
    elseif (0 === strpos($expression, 'child::')) {
      $expression = 'self::' . substr($expression, 7);
    }
    elseif ('/' === $expression[0] || 0 === strpos($expression, 'self::')) {

      // the only direct child in Symfony 2.4 and lower is _root, which is already handled previously
      // so let's drop the expression entirely
      $expression = $nonMatchingExpression;
    }
    elseif ('.' === $expression[0]) {

      // '.' is the fake root element in Symfony 2.4 and lower, which is excluded from results
      $expression = $nonMatchingExpression;
    }
    elseif (0 === strpos($expression, 'descendant::')) {
      $expression = 'descendant-or-self::' . substr($expression, strlen('descendant::'));
    }
    elseif (preg_match('/^(ancestor|ancestor-or-self|attribute|following|following-sibling|namespace|parent|preceding|preceding-sibling)::/', $expression)) {

      // the fake root has no parent, preceding or following nodes and also no attributes (even no namespace attributes)
      $expression = $nonMatchingExpression;
    }
    elseif (0 !== strpos($expression, 'descendant-or-self::')) {
      $expression = 'self::' . $expression;
    }
    $expressions[] = $parenthesis . $expression;
  }
  return implode(' | ', $expressions);
}