[ Index ] |
PHP Cross Reference of phpBB-3.3.14-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * @package s9e\TextFormatter 5 * @copyright Copyright (c) 2010-2022 The s9e authors 6 * @license http://www.opensource.org/licenses/mit-license.php The MIT License 7 */ 8 namespace s9e\TextFormatter\Configurator\Helpers; 9 10 use DOMAttr; 11 use DOMCharacterData; 12 use DOMDocument; 13 use DOMElement; 14 use DOMNode; 15 use DOMProcessingInstruction; 16 use DOMText; 17 use DOMXPath; 18 19 abstract class TemplateHelper 20 { 21 /** 22 * XSL namespace 23 */ 24 const XMLNS_XSL = 'http://www.w3.org/1999/XSL/Transform'; 25 26 /** 27 * Return a list of parameters in use in given XSL 28 * 29 * @param string $xsl XSL source 30 * @return array Alphabetically sorted list of unique parameter names 31 */ 32 public static function getParametersFromXSL($xsl) 33 { 34 $paramNames = []; 35 $xpath = new DOMXPath(TemplateLoader::load($xsl)); 36 37 // Start by collecting XPath expressions in XSL elements 38 $query = '//xsl:*/@match | //xsl:*/@select | //xsl:*/@test'; 39 foreach ($xpath->query($query) as $attribute) 40 { 41 $expr = $attribute->value; 42 $paramNames += array_flip(self::getParametersFromExpression($attribute, $expr)); 43 } 44 45 // Collect XPath expressions in attribute value templates 46 $query = '//*[namespace-uri() != "' . self::XMLNS_XSL . '"]/@*[contains(., "{")]'; 47 foreach ($xpath->query($query) as $attribute) 48 { 49 foreach (AVTHelper::parse($attribute->value) as $token) 50 { 51 if ($token[0] === 'expression') 52 { 53 $expr = $token[1]; 54 $paramNames += array_flip(self::getParametersFromExpression($attribute, $expr)); 55 } 56 } 57 } 58 59 // Sort the parameter names and return them in a list 60 ksort($paramNames); 61 62 return array_keys($paramNames); 63 } 64 65 /** 66 * Highlight the source of a node inside of a template 67 * 68 * @param DOMNode $node Node to highlight 69 * @param string $prepend HTML to prepend 70 * @param string $append HTML to append 71 * @return string Template's source, as HTML 72 */ 73 public static function highlightNode(DOMNode $node, $prepend, $append) 74 { 75 // Create a copy of the document that we can modify without side effects 76 $dom = $node->ownerDocument->cloneNode(true); 77 $dom->formatOutput = true; 78 79 $xpath = new DOMXPath($dom); 80 $node = $xpath->query($node->getNodePath())->item(0); 81 82 // Add a unique token to the node 83 $uniqid = uniqid('_'); 84 if ($node instanceof DOMAttr) 85 { 86 $node->value = htmlspecialchars($node->value, ENT_NOQUOTES, 'UTF-8') . $uniqid; 87 } 88 elseif ($node instanceof DOMElement) 89 { 90 $node->setAttribute($uniqid, ''); 91 } 92 elseif ($node instanceof DOMCharacterData || $node instanceof DOMProcessingInstruction) 93 { 94 $node->data .= $uniqid; 95 } 96 97 $docXml = TemplateLoader::innerXML($dom->documentElement); 98 $docXml = trim(str_replace("\n ", "\n", $docXml)); 99 100 $nodeHtml = htmlspecialchars(trim($dom->saveXML($node))); 101 $docHtml = htmlspecialchars($docXml); 102 103 // Enclose the node's representation in our highlighting HTML 104 $html = str_replace($nodeHtml, $prepend . $nodeHtml . $append, $docHtml); 105 106 // Remove the unique token from HTML 107 $html = str_replace(' ' . $uniqid . '=""', '', $html); 108 $html = str_replace($uniqid, '', $html); 109 110 return $html; 111 } 112 113 /** 114 * Replace simple templates (in an array, in-place) with a common template 115 * 116 * In some situations, renderers can take advantage of multiple tags having the same template. In 117 * any configuration, there's almost always a number of "simple" tags that are rendered as an 118 * HTML element of the same name with no HTML attributes. For instance, the system tag "p" used 119 * for paragraphs, "B" tags used for "b" HTML elements, etc... This method replaces those 120 * templates with a common template that uses a dynamic element name based on the tag's name, 121 * either its nodeName or localName depending on whether the tag is namespaced, and normalized to 122 * lowercase using XPath's translate() function 123 * 124 * @param array<string> &$templates Associative array of [tagName => template] 125 * @param integer $minCount 126 * @return void 127 */ 128 public static function replaceHomogeneousTemplates(array &$templates, $minCount = 3) 129 { 130 // Prepare the XPath expression used for the element's name 131 $expr = 'name()'; 132 133 // Identify "simple" tags, whose template is one element of the same name. Their template 134 // can be replaced with a dynamic template shared by all the simple tags 135 $tagNames = []; 136 foreach ($templates as $tagName => $template) 137 { 138 // Generate the element name based on the tag's localName, lowercased 139 $elName = strtolower(preg_replace('/^[^:]+:/', '', $tagName)); 140 if ($template === '<' . $elName . '><xsl:apply-templates/></' . $elName . '>') 141 { 142 $tagNames[] = $tagName; 143 144 // Use local-name() if any of the tags are namespaced 145 if (strpos($tagName, ':') !== false) 146 { 147 $expr = 'local-name()'; 148 } 149 } 150 } 151 152 // We only bother replacing their template if there are at least $minCount simple tags. 153 // Otherwise it only makes the stylesheet bigger 154 if (count($tagNames) < $minCount) 155 { 156 return; 157 } 158 159 // Generate a list of uppercase characters from the tags' names 160 $chars = preg_replace('/[^A-Z]+/', '', count_chars(implode('', $tagNames), 3)); 161 if ($chars > '') 162 { 163 $expr = 'translate(' . $expr . ",'" . $chars . "','" . strtolower($chars) . "')"; 164 } 165 166 // Prepare the common template 167 $template = '<xsl:element name="{' . $expr . '}"><xsl:apply-templates/></xsl:element>'; 168 169 // Replace the templates 170 foreach ($tagNames as $tagName) 171 { 172 $templates[$tagName] = $template; 173 } 174 } 175 176 /** 177 * Get a list of parameters from given XPath expression 178 * 179 * @param DOMNode $node Context node 180 * @param string $expr XPath expression 181 * @return string[] 182 */ 183 protected static function getParametersFromExpression(DOMNode $node, $expr) 184 { 185 $varNames = XPathHelper::getVariables($expr); 186 $paramNames = []; 187 $xpath = new DOMXPath($node->ownerDocument); 188 foreach ($varNames as $name) 189 { 190 // Test whether this is the name of a local variable 191 $query = 'ancestor-or-self::*/preceding-sibling::xsl:variable[@name="' . $name . '"]'; 192 if (!$xpath->query($query, $node)->length) 193 { 194 $paramNames[] = $name; 195 } 196 } 197 198 return $paramNames; 199 } 200 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Nov 25 19:05:08 2024 | Cross-referenced by PHPXref 0.7.1 |