getDomDocument()); $xpathNamespaces = $document->getXpathNamespaces(); foreach ($xpathNamespaces as $prefix => $namespaceUri) { $xpath->registerNamespace((string) $prefix, $namespaceUri); } if ($xpathPhpfunctions = $document->getXpathPhpFunctions()) { $xpath->registerNamespace('php', 'http://php.net/xpath'); if ($xpathPhpfunctions === true) { $xpath->registerPhpFunctions(); } else { $xpath->registerPhpFunctions($xpathPhpfunctions); } } $nodeList = $xpath->queryWithErrorException($expression, $contextNode); return new NodeList($nodeList); } /** * Transform CSS expression to XPath * * @param string $path * @return string */ public static function cssToXpath($path) { $path = (string) $path; if (strstr($path, ',')) { $paths = explode(',', $path); $expressions = []; foreach ($paths as $path) { $xpath = static::cssToXpath(trim($path)); if (is_string($xpath)) { $expressions[] = $xpath; } elseif (is_array($xpath)) { $expressions = array_merge($expressions, $xpath); } } return implode('|', $expressions); } do { $placeholder = '{' . uniqid((string) mt_rand(), true) . '}'; } while (strpos($path, $placeholder) !== false); // Arbitrary attribute value contains whitespace $path = preg_replace_callback( '/\[\S+?([\'"])((?!\1|\\\1).*?)\1\]/', function ($matches) use ($placeholder) { return str_replace($matches[2], preg_replace('/\s+/', $placeholder, $matches[2]), $matches[0]); }, $path ); $paths = ['//']; $path = preg_replace('|\s*>\s*|', '>', $path); $segments = preg_split('/\s+/', $path); $segments = str_replace($placeholder, ' ', $segments); foreach ($segments as $key => $segment) { $pathSegment = static::_tokenize($segment); if (0 === $key) { if (0 === strpos($pathSegment, '[contains(')) { $paths[0] .= '*' . ltrim($pathSegment, '*'); } else { $paths[0] .= $pathSegment; } continue; } if (0 === strpos($pathSegment, '[contains(')) { foreach ($paths as $pathKey => $xpath) { $paths[$pathKey] .= '//*' . ltrim($pathSegment, '*'); $paths[] = $xpath . $pathSegment; } } else { foreach ($paths as $pathKey => $xpath) { $paths[$pathKey] .= '//' . $pathSegment; } } } if (1 === count($paths)) { return $paths[0]; } return implode('|', $paths); } // @codingStandardsIgnoreStart /** * Tokenize CSS expressions to XPath * * @param string $expression * @return string */ protected static function _tokenize($expression) { // @codingStandardsIgnoreEnd // Child selectors $expression = str_replace('>', '/', $expression); // IDs $expression = preg_replace('|#([a-z][a-z0-9_-]*)|i', '[@id=\'$1\']', $expression); $expression = preg_replace('|(?