Completed
Branch TemplateNormalizations (ae42e4)
by Josh
33:16
created

AbstractNormalization::createTextNode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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