Completed
Push — master ( f7b88b...3755ed )
by Josh
14:40
created

AbstractNormalization::createElement()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 2
1
<?php
2
3
/**
4
* @package   s9e\TextFormatter
5
* @copyright Copyright (c) 2010-2017 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
		$value = htmlspecialchars($textContent, ENT_NOQUOTES, 'UTF-8');
70
		$pos   = strpos($nodeName, ':');
71
		if ($pos === false)
72
		{
73
			return $this->ownerDocument->createElement($nodeName, $value);
74
		}
75
76
		$namespaceURI = $this->ownerDocument->lookupNamespaceURI(substr($nodeName, 0, $pos));
77
78
		return $this->ownerDocument->createElementNS($namespaceURI, $nodeName, $value);
79
	}
80
81
	/**
82
	* Create a text node in current template
83
	*
84
	* @param  string  $content
85
	* @return DOMText
86
	*/
87
	protected function createTextNode($content)
88
	{
89
		return $this->ownerDocument->createTextNode($content);
90
	}
91
92
	/**
93
	* Query and return a list of nodes of interest
94
	*
95
	* @return DOMNode[]
96
	*/
97
	protected function getNodes()
98
	{
99
		$query = implode(' | ', $this->queries);
100
101
		return ($query === '') ? [] : $this->xpath($query);
102
	}
103
104
	/**
105
	* Test whether given node is an XSL element
106
	*
107
	* @param  DOMNode $node
108
	* @param  string  $localName
109
	* @return bool
110
	*/
111
	protected function isXsl(DOMNode $node, $localName = null)
112
	{
113
		return ($node->namespaceURI === self::XMLNS_XSL && (!isset($localName) || $localName === $node->localName));
114
	}
115
116
	/**
117
	* Make an ASCII string lowercase
118
	*
119
	* @param  string $str Original string
120
	* @return string      Lowercased string
121
	*/
122
	protected function lowercase($str)
123
	{
124
		return strtr($str, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
125
	}
126
127
	/**
128
	* Normalize given attribute
129
	*
130
	* @param  DOMAttr $attribute
131
	* @return void
132
	*/
133
	protected function normalizeAttribute(DOMAttr $attribute)
134
	{
135
	}
136
137
	/**
138
	* Normalize given element
139
	*
140
	* @param  DOMElement $element
141
	* @return void
142
	*/
143
	protected function normalizeElement(DOMElement $element)
144
	{
145
	}
146
147
	/**
148
	* Normalize given node
149
	*
150
	* @param  DOMNode $node
151
	* @return void
152
	*/
153
	protected function normalizeNode(DOMNode $node)
154
	{
155
		if (!$node->parentNode)
156
		{
157
			// Ignore nodes that have been removed from the document
158
			return;
159
		}
160
		if ($node instanceof DOMElement)
161
		{
162
			$this->normalizeElement($node);
163
		}
164
		elseif ($node instanceof DOMAttr)
165
		{
166
			$this->normalizeAttribute($node);
167
		}
168
	}
169
170
	/**
171
	* Reset this instance's properties after usage
172
	*
173
	* @return void
174
	*/
175
	protected function reset()
176
	{
177
		$this->ownerDocument = null;
178
		$this->xpath         = null;
179
	}
180
181
	/**
182
	* Evaluate given XPath expression
183
	*
184
	* For convenience, $XSL is replaced with the XSL namespace URI as a string
185
	*
186
	* @param  string    $query XPath query
187
	* @param  DOMNode   $node  Context node
188
	* @return DOMNode[]
189
	*/
190
	protected function xpath($query, DOMNode $node = null)
191
	{
192
		$query = str_replace('$XSL', '"' . self::XMLNS_XSL . '"', $query);
193
194
		return iterator_to_array($this->xpath->query($query, $node));
195
	}
196
}