normalizer = new TemplateNormalizer([ 'MergeConsecutiveCopyOf', 'MergeIdenticalConditionalBranches', 'OptimizeNestedConditionals', 'RemoveLivePreviewAttributes' ]); } /** * {@inheritdoc} */ public function getRenderer(Rendering $rendering) { return new XSLTRenderer($this->getXSL($rendering)); } /** * Generate an XSL stylesheet based on given rendering configuration * * @param Rendering $rendering * @return string */ public function getXSL(Rendering $rendering) { $groupedTemplates = []; $templates = $rendering->getTemplates(); // Replace simple templates if there are at least 3 of them TemplateHelper::replaceHomogeneousTemplates($templates, 3); // Group tags with identical templates together foreach ($templates as $tagName => $template) { $template = $this->normalizer->normalizeTemplate($template); $groupedTemplates[$template][] = $tagName; } // Declare all the namespaces in use at the top $xsl = 'getPrefixes(array_keys($templates)); if (!empty($prefixes)) { foreach ($prefixes as $prefix) { $xsl .= ' xmlns:' . $prefix . '="urn:s9e:TextFormatter:' . $prefix . '"'; } /** * Exclude those prefixes to keep the HTML neat * * @link http://lenzconsulting.com/namespaces-in-xslt/#exclude-result-prefixes */ $xsl .= ' exclude-result-prefixes="' . implode(' ', $prefixes) . '"'; } // Start the stylesheet with the boilerplate stuff $xsl .= '>'; // Add stylesheet parameters foreach ($rendering->getAllParameters() as $paramName => $paramValue) { $xsl .= $this->writeTag('xsl:param', ['name' => $paramName], htmlspecialchars($paramValue, ENT_NOQUOTES)); } // Add templates foreach ($groupedTemplates as $template => $tagNames) { $xsl .= $this->writeTag('xsl:template', ['match' => implode('|', $tagNames)], $template); } $xsl .= ''; return $xsl; } /** * Extract and return the sorted list of prefixes used in given list of tag names * * @param string[] $tagNames * @return string[] */ protected function getPrefixes(array $tagNames) { $prefixes = []; foreach ($tagNames as $tagName) { $pos = strpos($tagName, ':'); if ($pos !== false) { $prefixes[substr($tagName, 0, $pos)] = 1; } } $prefixes = array_keys($prefixes); sort($prefixes); return $prefixes; } /** * Serialize given tag to XML * * @param string $tagName * @param array $attributes * @param string $content * @return string */ protected function writeTag($tagName, array $attributes, $content) { $xml = '<' . $tagName; foreach ($attributes as $attrName => $attrValue) { $xml .= ' ' . $attrName . '="' . htmlspecialchars($attrValue, ENT_COMPAT, 'utf-8') . '"'; } if ($content === '') { $xml .= '/>'; } else { $xml .= '>' . $content . ''; } return $xml; } }