Symfony\Component\DomCrawler\Crawler::relativize PHP Method

relativize() private method

The returned XPath will match elements matching the XPath inside the current crawler when running in the context of a node of the crawler.
private relativize ( string $xpath ) : string
$xpath string
return string
    private function relativize($xpath)
    {
        $expressions = array();
        // An expression which will never match to replace expressions which cannot match in the crawler
        // We cannot simply drop
        $nonMatchingExpression = 'a[name() = "b"]';
        $xpathLen = strlen($xpath);
        $openedBrackets = 0;
        $startPosition = strspn($xpath, " \t\n\r\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\v", $startPosition + 1);
                $parenthesis = substr($xpath, $startPosition, $j);
                $startPosition += $j;
            } else {
                $parenthesis = '';
            }
            $expression = rtrim(substr($xpath, $startPosition, $i - $startPosition));
            if (0 === strpos($expression, 'self::*/')) {
                $expression = './' . substr($expression, 8);
            }
            // add prefix before absolute element selector
            if ('' === $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] || '.' === $expression[0] || 0 === strpos($expression, 'self::')) {
                $expression = $nonMatchingExpression;
            } elseif (0 === strpos($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 (0 !== strpos($expression, 'descendant-or-self::')) {
                $expression = 'self::' . $expression;
            }
            $expressions[] = $parenthesis . $expression;
            if ($i === $xpathLen) {
                return implode(' | ', $expressions);
            }
            $i += strspn($xpath, " \t\n\r\v", $i + 1);
            $startPosition = $i + 1;
        }
        return $xpath;
        // The XPath expression is invalid
    }