Completed
Push — master ( 40adb2...bf24e0 )
by Josh
04:00
created

XSLT   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 134
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 14
lcom 1
cbo 4
dl 0
loc 134
ccs 41
cts 41
cp 1
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A getRenderer() 0 4 1
A __construct() 0 4 1
B getXSL() 0 54 6
A getPrefixes() 0 16 3
A writeTag() 0 18 3
1
<?php
2
3
/**
4
* @package   s9e\TextFormatter
5
* @copyright Copyright (c) 2010-2019 The s9e Authors
6
* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
7
*/
8
namespace s9e\TextFormatter\Configurator\RendererGenerators;
9
10
use s9e\TextFormatter\Configurator\Helpers\TemplateHelper;
11
use s9e\TextFormatter\Configurator\RendererGenerator;
12
use s9e\TextFormatter\Configurator\RendererGenerators\XSLT\Optimizer;
13
use s9e\TextFormatter\Configurator\Rendering;
14
use s9e\TextFormatter\Renderers\XSLT as XSLTRenderer;
15
16
class XSLT implements RendererGenerator
17
{
18
	/**
19
	* @var Optimizer
20
	*/
21
	public $optimizer;
22
23
	/**
24
	* Constructor
25
	*/
26 11
	public function __construct()
27
	{
28 11
		$this->optimizer = new Optimizer;
29
	}
30
31
	/**
32
	* {@inheritdoc}
33
	*/
34 1
	public function getRenderer(Rendering $rendering)
35
	{
36 1
		return new XSLTRenderer($this->getXSL($rendering));
37
	}
38
39
	/**
40
	* Generate an XSL stylesheet based on given rendering configuration
41
	*
42
	* @param  Rendering $rendering
43
	* @return string
44
	*/
45 11
	public function getXSL(Rendering $rendering)
46
	{
47 11
		$groupedTemplates = [];
48 11
		$templates        = $rendering->getTemplates();
49
50
		// Replace simple templates if there are at least 3 of them
51 11
		TemplateHelper::replaceHomogeneousTemplates($templates, 3);
52
53
		// Group tags with identical templates together
54 11
		foreach ($templates as $tagName => $template)
55
		{
56 11
			$template = $this->optimizer->optimizeTemplate($template);
57 11
			$groupedTemplates[$template][] = $tagName;
58
		}
59
60
		// Declare all the namespaces in use at the top
61 11
		$xsl = '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"';
62
63
		// Append the namespace declarations to the stylesheet
64 11
		$prefixes = $this->getPrefixes(array_keys($templates));
65 11
		if (!empty($prefixes))
66
		{
67 2
			foreach ($prefixes as $prefix)
68
			{
69 2
				$xsl .= ' xmlns:' . $prefix . '="urn:s9e:TextFormatter:' . $prefix . '"';
70
			}
71
72
			/**
73
			* Exclude those prefixes to keep the HTML neat
74
			*
75
			* @link http://lenzconsulting.com/namespaces-in-xslt/#exclude-result-prefixes
76
			*/
77 2
			$xsl .= ' exclude-result-prefixes="' . implode(' ', $prefixes) . '"';
78
		}
79
80
		// Start the stylesheet with the boilerplate stuff
81 11
		$xsl .= '><xsl:output method="html" encoding="utf-8" indent="no"/>';
82
83
		// Add stylesheet parameters
84 11
		foreach ($rendering->getAllParameters() as $paramName => $paramValue)
85
		{
86 3
			$xsl .= $this->writeTag('xsl:param', ['name' => $paramName], htmlspecialchars($paramValue, ENT_NOQUOTES));
87
		}
88
89
		// Add templates
90 11
		foreach ($groupedTemplates as $template => $tagNames)
91
		{
92 11
			$xsl .= $this->writeTag('xsl:template', ['match' => implode('|', $tagNames)], $template);
93
		}
94
95 11
		$xsl .= '</xsl:stylesheet>';
96
97 11
		return $xsl;
98
	}
99
100
	/**
101
	* Extract and return the sorted list of prefixes used in given list of tag names
102
	*
103
	* @param  string[] $tagNames
104
	* @return string[]
105
	*/
106 11
	protected function getPrefixes(array $tagNames)
107
	{
108 11
		$prefixes = [];
109 11
		foreach ($tagNames as $tagName)
110
		{
111 11
			$pos = strpos($tagName, ':');
112 11
			if ($pos !== false)
113
			{
114 2
				$prefixes[substr($tagName, 0, $pos)] = 1;
115
			}
116
		}
117 11
		$prefixes = array_keys($prefixes);
118 11
		sort($prefixes);
119
120 11
		return $prefixes;
121
	}
122
123
	/**
124
	* Serialize given tag to XML
125
	*
126
	* @param  string $tagName
127
	* @param  array  $attributes
128
	* @param  string $content
129
	* @return string
130
	*/
131 11
	protected function writeTag($tagName, array $attributes, $content)
132
	{
133 11
		$xml = '<' . $tagName;
134 11
		foreach ($attributes as $attrName => $attrValue)
135
		{
136 11
			$xml .= ' ' . $attrName . '="' . htmlspecialchars($attrValue) . '"';
137
		}
138 11
		if ($content === '')
139
		{
140 11
			$xml .= '/>';
141
		}
142
		else
143
		{
144 11
			$xml .= '>' . $content . '</' . $tagName . '>';
145
		}
146
147 11
		return $xml;
148
	}
149
}