Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. Crawler.php

function 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.

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 947

Class

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

Namespace

Symfony\Component\DomCrawler

Code

private function relativize(string $xpath) : string {
    $expressions = [];
    // An expression which will never match to replace expressions which cannot match in the crawler
    // We cannot drop
    $nonMatchingExpression = 'a[name() = "b"]';
    $xpathLen = \strlen($xpath);
    $openedBrackets = 0;
    $startPosition = strspn($xpath, " \t\n\r\x00\v");
    for ($i = $startPosition; $i <= $xpathLen; ++$i) {
        $i += strcspn($xpath, '"\'[]|', $i);
        if ($i < $xpathLen) {
            switch ($xpath[$i]) {
                case '"':
                case "'":
                    if (false === ($i = strpos($xpath, $xpath[$i], $i + 1))) {
                        return $xpath;
                        // The XPath expression is invalid
                    }
                    continue 2;
                case '[':
                    ++$openedBrackets;
                    continue 2;
                case ']':
                    --$openedBrackets;
                    continue 2;
            }
        }
        if ($openedBrackets) {
            continue;
        }
        if ($startPosition < $xpathLen && '(' === $xpath[$startPosition]) {
            // If the union is inside some braces, we need to preserve the opening braces and apply
            // the change only inside it.
            $j = 1 + strspn($xpath, "( \t\n\r\x00\v", $startPosition + 1);
            $parenthesis = substr($xpath, $startPosition, $j);
            $startPosition += $j;
        }
        else {
            $parenthesis = '';
        }
        $expression = rtrim(substr($xpath, $startPosition, $i - $startPosition));
        if (str_starts_with($expression, 'self::*/')) {
            $expression = './' . substr($expression, 8);
        }
        // add prefix before absolute element selector
        if ('' === $expression) {
            $expression = $nonMatchingExpression;
        }
        elseif (str_starts_with($expression, '//')) {
            $expression = 'descendant-or-self::' . substr($expression, 2);
        }
        elseif (str_starts_with($expression, './/')) {
            $expression = 'descendant-or-self::' . substr($expression, 3);
        }
        elseif (str_starts_with($expression, './')) {
            $expression = 'self::' . substr($expression, 2);
        }
        elseif (str_starts_with($expression, 'child::')) {
            $expression = 'self::' . substr($expression, 7);
        }
        elseif ('/' === $expression[0] || '.' === $expression[0] || str_starts_with($expression, 'self::')) {
            $expression = $nonMatchingExpression;
        }
        elseif (str_starts_with($expression, 'descendant::')) {
            $expression = 'descendant-or-self::' . substr($expression, 12);
        }
        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 (!str_starts_with($expression, 'descendant-or-self::')) {
            $expression = 'self::' . $expression;
        }
        $expressions[] = $parenthesis . $expression;
        if ($i === $xpathLen) {
            return implode(' | ', $expressions);
        }
        $i += strspn($xpath, " \t\n\r\x00\v", $i + 1);
        $startPosition = $i + 1;
    }
    return $xpath;
    // The XPath expression is invalid
}
RSS feed
Powered by Drupal