protectMagentoDirectives($html); $document = $this->createDocument($protectedHtml); $xpath = new DOMXPath($document); $query = sprintf( '//*[@id="%s"]//text()[normalize-space(.) != "" and not(ancestor::script) and not(ancestor::style) and not(ancestor::code) and not(ancestor::pre)]', self::ROOT_ID ); $nodes = $xpath->query($query); $textNodes = []; $texts = []; $index = 0; if ($nodes !== false) { foreach ($nodes as $node) { if (!$node instanceof DOMText) { continue; } $text = $this->restoreMagentoDirectives($node->nodeValue ?? '', $directivePlaceholders); if (trim($text) === '') { continue; } $id = 'html_' . $index++; $textNodes[$id] = $node; $texts[$id] = $text; } } $root = $document->getElementById(self::ROOT_ID); if (!$root) { throw new \RuntimeException('Unable to parse HTML fragment.'); } return new HtmlFragment($document, $root, $textNodes, $texts, $directivePlaceholders); } private function createDocument(string $html): DOMDocument { $document = new DOMDocument('1.0', 'UTF-8'); $wrappedHtml = sprintf( '
%s
', self::ROOT_ID, $html ); $previous = libxml_use_internal_errors(true); $loaded = $document->loadHTML($wrappedHtml, LIBXML_HTML_NODEFDTD | LIBXML_HTML_NOIMPLIED); libxml_clear_errors(); libxml_use_internal_errors($previous); if (!$loaded) { throw new \RuntimeException('Unable to parse HTML fragment.'); } return $document; } /** * @return array{0: string, 1: array} */ private function protectMagentoDirectives(string $html): array { $placeholders = []; $index = 0; $protected = preg_replace_callback( '/\{\{.*?\}\}/s', function (array $matches) use (&$placeholders, &$index): string { $token = self::DIRECTIVE_TOKEN_PREFIX . $index++ . '__'; $placeholders[$token] = $this->normalizeMagentoDirectiveQuotes($matches[0]); return $token; }, $html ); return [$protected ?? $html, $placeholders]; } /** * @param array $placeholders */ private function restoreMagentoDirectives(string $html, array $placeholders): string { $restored = $placeholders === [] ? $html : strtr($html, $placeholders); return $this->normalizeMagentoDirectiveQuotes($restored); } private function normalizeMagentoDirectiveQuotes(string $html): string { return preg_replace_callback( '/\{\{.*?\}\}/s', static function (array $matches): string { return str_ireplace( ['"', '"', '"', ''', ''', '''], ['"', '"', '"', "'", "'", "'"], $matches[0] ); }, $html ) ?? $html; } }