Completed
Push — master ( da9c65...78914a )
by Josh
14:53
created

AbstractNormalization::createText()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
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\TemplateNormalizations;
9
10
use DOMAttr;
11
use DOMComment;
12
use DOMElement;
13
use DOMNode;
14
use DOMXPath;
15
16
abstract class AbstractNormalization
17
{
18
	/**
19
	* XSL namespace
20
	*/
21
	const XMLNS_XSL = 'http://www.w3.org/1999/XSL/Transform';
22
23
	/**
24
	* @var bool Whether this normalization should be applied only once per template
25
	*/
26
	public $onlyOnce = false;
27
28
	/**
29
	* @var DOMDocument Document that holds the template being normalized
30
	*/
31
	protected $ownerDocument;
32
33
	/**
34
	* @var string[] XPath queries used to retrieve nodes of interest
35
	*/
36
	protected $queries = [];
37
38
	/**
39
	* @var DOMXPath
40
	*/
41
	protected $xpath;
42
43
	/**
44
	* Apply this normalization rule to given template
45
	*
46
	* @param  DOMElement $template <xsl:template/> node
47
	* @return void
48
	*/
49
	public function normalize(DOMElement $template)
50
	{
51
		$this->ownerDocument = $template->ownerDocument;
52
		$this->xpath         = new DOMXPath($this->ownerDocument);
53
		foreach ($this->getNodes() as $node)
54
		{
55
			$this->normalizeNode($node);
56
		}
57
		$this->reset();
58
	}
59
60
	/**
61
	* Create an element in current template
62
	*
63
	* @param  string     $nodeName
64
	* @param  string     $textContent
65
	* @return DOMElement
66
	*/
67
	protected function createElement($nodeName, $textContent = '')
68
	{
69
		$methodName = 'createElement';
70
		$args       = [$nodeName];
71
72
		// Add the text content for the new element
73
		if ($textContent !== '')
74
		{
75
			$args[] = htmlspecialchars($textContent, ENT_NOQUOTES, 'UTF-8');
76
		}
77
78
		// Handle namespaced elements
79
		$prefix = strstr($nodeName, ':', true);
80
		if ($prefix > '')
81
		{
82
			$methodName .= 'NS';
83
			array_unshift($args, $this->ownerDocument->lookupNamespaceURI($prefix));
84
		}
85
86
		return call_user_func_array([$this->ownerDocument, $methodName], $args);
87
	}
88
89
	/**
90
	* Create an xsl:text element or a text node in current template
91
	*
92
	* @param  string  $content
93
	* @return DOMNode
94
	*/
95
	protected function createText($content)
96
	{
97
		return (trim($content) === '')
98
		     ? $this->createElement('xsl:text', $content)
99
		     : $this->ownerDocument->createTextNode($content);
100
	}
101
102
	/**
103
	* Create a text node in current template
104
	*
105
	* @param  string  $content
106
	* @return DOMText
107
	*/
108
	protected function createTextNode($content)
109
	{
110
		return $this->ownerDocument->createTextNode($content);
111
	}
112
113
	/**
114
	* Query and return a list of nodes of interest
115
	*
116
	* @return DOMNode[]
117
	*/
118
	protected function getNodes()
119
	{
120
		$query = implode(' | ', $this->queries);
121
122
		return ($query === '') ? [] : $this->xpath($query);
123
	}
124
125
	/**
126
	* Test whether given node is an XSL element
127
	*
128
	* @param  DOMNode $node
129
	* @param  string  $localName
130
	* @return bool
131
	*/
132
	protected function isXsl(DOMNode $node, $localName = null)
133
	{
134
		return ($node->namespaceURI === self::XMLNS_XSL && (!isset($localName) || $localName === $node->localName));
135
	}
136
137
	/**
138
	* Make an ASCII string lowercase
139
	*
140
	* @param  string $str Original string
141
	* @return string      Lowercased string
142
	*/
143
	protected function lowercase($str)
144
	{
145
		return strtr($str, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
146
	}
147
148
	/**
149
	* Normalize given attribute
150
	*
151
	* @param  DOMAttr $attribute
152
	* @return void
153
	*/
154
	protected function normalizeAttribute(DOMAttr $attribute)
155
	{
156
	}
157
158
	/**
159
	* Normalize given element
160
	*
161
	* @param  DOMElement $element
162
	* @return void
163
	*/
164
	protected function normalizeElement(DOMElement $element)
165
	{
166
	}
167
168
	/**
169
	* Normalize given node
170
	*
171
	* @param  DOMNode $node
172
	* @return void
173
	*/
174
	protected function normalizeNode(DOMNode $node)
175
	{
176
		if (!$node->parentNode)
177
		{
178
			// Ignore nodes that have been removed from the document
179
			return;
180
		}
181
		if ($node instanceof DOMElement)
182
		{
183
			$this->normalizeElement($node);
184
		}
185
		elseif ($node instanceof DOMAttr)
186
		{
187
			$this->normalizeAttribute($node);
188
		}
189
	}
190
191
	/**
192
	* Reset this instance's properties after usage
193
	*
194
	* @return void
195
	*/
196
	protected function reset()
197
	{
198
		$this->ownerDocument = null;
199
		$this->xpath         = null;
200
	}
201
202
	/**
203
	* Evaluate given XPath expression
204
	*
205
	* For convenience, $XSL is replaced with the XSL namespace URI as a string
206
	*
207
	* @param  string    $query XPath query
208
	* @param  DOMNode   $node  Context node
209
	* @return DOMNode[]
210
	*/
211
	protected function xpath($query, DOMNode $node = null)
212
	{
213
		$query = str_replace('$XSL', '"' . self::XMLNS_XSL . '"', $query);
214
215
		return iterator_to_array($this->xpath->query($query, $node));
216
	}
217
}