/** * Generate an XSL stylesheet based on given rendering configuration * * @param Rendering $rendering * @return string */ public function getXSL(Rendering $rendering) { $groupedTemplates = []; $prefixes = []; $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->optimizer->optimizeTemplate($template); $groupedTemplates[$template][] = $tagName; // Record the tag's prefix if applicable $pos = strpos($tagName, ':'); if ($pos !== false) { $prefixes[substr($tagName, 0, $pos)] = 1; } } // Declare all the namespaces in use at the top $xsl = '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"'; // Append the namespace declarations to the stylesheet $prefixes = array_keys($prefixes); sort($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 */ if (!empty($prefixes)) { $xsl .= ' exclude-result-prefixes="' . implode(' ', $prefixes) . '"'; } // Start the stylesheet with the boilerplate stuff $xsl .= '><xsl:output method="html" encoding="utf-8" indent="no"'; $xsl .= '/>'; // Add stylesheet parameters foreach ($rendering->getAllParameters() as $paramName => $paramValue) { $xsl .= '<xsl:param name="' . htmlspecialchars($paramName) . '"'; if ($paramValue === '') { $xsl .= '/>'; } else { $xsl .= '>' . htmlspecialchars($paramValue) . '</xsl:param>'; } } // Add templates foreach ($groupedTemplates as $template => $tagNames) { // Open the template element $xsl .= '<xsl:template match="' . implode('|', $tagNames) . '"'; // Make it a self-closing element if the template is empty if ($template === '') { $xsl .= '/>'; } else { $xsl .= '>' . $template . '</xsl:template>'; } } $xsl .= '</xsl:stylesheet>'; return $xsl; }
protected function addSiteId($siteId, $template) { $dom = TemplateHelper::loadTemplate($template); $xpath = new DOMXPath($dom); $query = '//*[namespace-uri() != "' . TemplateHelper::XMLNS_XSL . '"][not(ancestor::*[namespace-uri() != "' . TemplateHelper::XMLNS_XSL . '"])]'; foreach ($xpath->query($query) as $element) { $element->setAttribute('data-s9e-mediaembed', $siteId); } return TemplateHelper::saveTemplate($dom); }
/** * Normalize URLs * * @link http://dev.w3.org/html5/spec/links.html#attr-hyperlink-href * * @param DOMElement $template <xsl:template/> node * @return void */ public function normalize(DOMElement $template) { foreach (TemplateHelper::getURLNodes($template->ownerDocument) as $node) { if ($node instanceof DOMAttr) { $this->normalizeAttribute($node); } elseif ($node instanceof DOMElement) { $this->normalizeElement($node); } } }
/** * @testdox Works * @dataProvider getData */ public function test($template, $expected, $preserveWhiteSpace = null) { if ($expected instanceof Exception) { $this->setExpectedException(get_class($expected), $expected->getMessage()); } $xml = '<xsl:template xmlns:xsl="http://www.w3.org/1999/XSL/Transform">' . $template . '</xsl:template>'; $dom = new DOMDocument(); $dom->loadXML($xml); $className = preg_replace('/.*\\\\(.*?)Test$/', 's9e\\TextFormatter\\Configurator\\TemplateNormalizations\\\\$1', get_class($this)); $normalizer = new $className(); $normalizer->normalize($dom->documentElement); $this->assertSame($expected, TemplateHelper::saveTemplate($dom)); }
public function getXSL(Rendering $rendering) { $groupedTemplates = array(); $prefixes = array(); $templates = $rendering->getTemplates(); TemplateHelper::replaceHomogeneousTemplates($templates, 3); foreach ($templates as $tagName => $template) { $template = $this->optimizer->optimizeTemplate($template); $groupedTemplates[$template][] = $tagName; $pos = \strpos($tagName, ':'); if ($pos !== \false) { $prefixes[\substr($tagName, 0, $pos)] = 1; } } $xsl = '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"'; $prefixes = \array_keys($prefixes); \sort($prefixes); foreach ($prefixes as $prefix) { $xsl .= ' xmlns:' . $prefix . '="urn:s9e:TextFormatter:' . $prefix . '"'; } if (!empty($prefixes)) { $xsl .= ' exclude-result-prefixes="' . \implode(' ', $prefixes) . '"'; } $xsl .= '><xsl:output method="html" encoding="utf-8" indent="no"'; $xsl .= '/>'; foreach ($rendering->getAllParameters() as $paramName => $paramValue) { $xsl .= '<xsl:param name="' . \htmlspecialchars($paramName) . '"'; if ($paramValue === '') { $xsl .= '/>'; } else { $xsl .= '>' . \htmlspecialchars($paramValue) . '</xsl:param>'; } } foreach ($groupedTemplates as $template => $tagNames) { $xsl .= '<xsl:template match="' . \implode('|', $tagNames) . '"'; if ($template === '') { $xsl .= '/>'; } else { $xsl .= '>' . $template . '</xsl:template>'; } } $xsl .= '</xsl:stylesheet>'; return $xsl; }
public function saveChanges() { $this->template->setContent(TemplateHelper::saveTemplate($this)); }
public function normalizeValue($value) { return TemplateHelper::saveTemplate(TemplateHelper::loadTemplate($value)); }
/** * Parse given template and store the references it contains * * @param string $template * @return void */ protected function parseTemplate($template) { $this->references = ['anywhere' => [], 'asUrl' => [], 'inText' => []]; preg_match_all($this->referencesRegexp, $template, $matches); foreach ($matches[0] as $match) { $key = trim($match, '\\${}'); $this->references['anywhere'][$key] = $key; } $dom = TemplateHelper::loadTemplate($template); $xpath = new DOMXPath($dom); foreach ($xpath->query('//text()') as $node) { preg_match_all($this->referencesRegexp, $node->textContent, $matches); foreach ($matches[0] as $match) { $key = trim($match, '\\${}'); $this->references['inText'][$key] = $key; } } foreach (TemplateHelper::getURLNodes($dom) as $node) { // We only bother with literal attributes that start with a capture if ($node instanceof DOMAttr && preg_match('(^(?:[$\\\\]\\d+|\\$\\{\\d+\\}))', trim($node->value), $m)) { $key = trim($m[0], '\\${}'); $this->references['asUrl'][$key] = $key; } } $this->removeUnknownReferences(); }
public function highlightNode($prepend = '<span style="background-color:#ff0">', $append = '</span>') { return TemplateHelper::highlightNode($this->node, $prepend, $append); }
/** * {@inheritdoc} */ protected function getNodes(DOMElement $template) { return TemplateHelper::getURLNodes($template->ownerDocument); }
/** * Check a given template for disallowed content * * @param string $template Template * @param Tag $tag Tag this template belongs to * @return void */ public function checkTemplate($template, Tag $tag = null) { if ($this->disabled) { return; } if (!isset($tag)) { $tag = new Tag(); } // Load the template into a DOMDocument $dom = TemplateHelper::loadTemplate($template); foreach ($this->collection as $check) { $check->check($dom->documentElement, $tag); } }
/** * @testdox replaceHomogeneousTemplates() tests * @dataProvider getReplaceHomogeneousTemplatesTests */ public function testReplaceHomogeneousTemplates($templates, $expected) { TemplateHelper::replaceHomogeneousTemplates($templates); $this->assertSame($expected, $templates); }
protected function parseTemplate($template) { $this->references = array('anywhere' => array(), 'asUrl' => array(), 'inText' => array()); \preg_match_all($this->referencesRegexp, $template, $matches); foreach ($matches[0] as $match) { $key = \trim($match, '\\${}'); $this->references['anywhere'][$key] = $key; } $dom = TemplateHelper::loadTemplate($template); $xpath = new DOMXPath($dom); foreach ($xpath->query('//text()') as $node) { \preg_match_all($this->referencesRegexp, $node->textContent, $matches); foreach ($matches[0] as $match) { $key = \trim($match, '\\${}'); $this->references['inText'][$key] = $key; } } foreach (TemplateHelper::getURLNodes($dom) as $node) { if ($node instanceof DOMAttr && \preg_match('(^(?:[$\\\\]\\d+|\\$\\{\\d+\\}))', \trim($node->value), $m)) { $key = \trim($m[0], '\\${}'); $this->references['asUrl'][$key] = $key; } } $this->removeUnknownReferences(); }
/** * Normalize a template * * @param string $template Original template * @return string Normalized template */ public function normalizeTemplate($template) { $dom = TemplateHelper::loadTemplate($template); // We'll keep track of what normalizations have been applied $applied = []; // Apply all the normalizations until no more change is made or we've reached the maximum // number of loops $loops = 5; do { $old = $template; foreach ($this->collection as $k => $normalization) { if (isset($applied[$k]) && !empty($normalization->onlyOnce)) { continue; } $normalization->normalize($dom->documentElement); $applied[$k] = 1; } $template = TemplateHelper::saveTemplate($dom); } while (--$loops && $template !== $old); return $template; }
/** * Replace parts of this template that match given regexp * * @param string $regexp Regexp for matching parts that need replacement * @param callback $fn Callback used to get the replacement * @return void */ public function replaceTokens($regexp, $fn) { $this->forensics = null; $this->template = TemplateHelper::replaceTokens($this->template, $regexp, $fn); $this->isNormalized = false; }