[ Index ]

PHP Cross Reference of phpBB-3.3.14-deutsch

title

Body

[close]

/vendor/s9e/text-formatter/src/Configurator/Helpers/ -> TemplateHelper.php (source)

   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 . '=&quot;&quot;', '', $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  }


Generated: Mon Nov 25 19:05:08 2024 Cross-referenced by PHPXref 0.7.1