Completed
Push — master ( 2f74e5...c5dbe4 )
by Josh
17:21
created

NodeLocator::getAttributesByRegexp()   C

Complexity

Conditions 8
Paths 27

Size

Total Lines 35
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 35
rs 5.3846
c 0
b 0
f 0
cc 8
eloc 14
nc 27
nop 2
1
<?php
2
3
/**
4
* @package   s9e\TextFormatter
5
* @copyright Copyright (c) 2010-2018 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 DOMDocument;
11
use DOMXPath;
12
13
abstract class NodeLocator
14
{
15
	/**
16
	* Return all attributes (literal or generated) that match given regexp
17
	*
18
	* @param  DOMDocument $dom    Document
19
	* @param  string      $regexp Regexp
20
	* @return array               Array of DOMNode instances
21
	*/
22
	public static function getAttributesByRegexp(DOMDocument $dom, $regexp)
23
	{
24
		$xpath = new DOMXPath($dom);
25
		$nodes = [];
26
27
		// Get literal attributes
28
		foreach ($xpath->query('//@*') as $attribute)
29
		{
30
			if (preg_match($regexp, $attribute->name))
31
			{
32
				$nodes[] = $attribute;
33
			}
34
		}
35
36
		// Get generated attributes
37
		foreach ($xpath->query('//xsl:attribute') as $attribute)
38
		{
39
			if (preg_match($regexp, $attribute->getAttribute('name')))
40
			{
41
				$nodes[] = $attribute;
42
			}
43
		}
44
45
		// Get attributes created with <xsl:copy-of/>
46
		foreach ($xpath->query('//xsl:copy-of') as $node)
47
		{
48
			$expr = $node->getAttribute('select');
49
			if (preg_match('/^@(\\w+)$/', $expr, $m) && preg_match($regexp, $m[1]))
50
			{
51
				$nodes[] = $node;
52
			}
53
		}
54
55
		return $nodes;
56
	}
57
58
	/**
59
	* Return all DOMNodes whose content is CSS
60
	*
61
	* @param  DOMDocument $dom Document
62
	* @return array            Array of DOMNode instances
63
	*/
64
	public static function getCSSNodes(DOMDocument $dom)
65
	{
66
		$regexp = '/^style$/i';
67
		$nodes  = array_merge(
68
			self::getAttributesByRegexp($dom, $regexp),
69
			self::getElementsByRegexp($dom, '/^style$/i')
70
		);
71
72
		return $nodes;
73
	}
74
75
	/**
76
	* Return all elements (literal or generated) that match given regexp
77
	*
78
	* @param  DOMDocument $dom    Document
79
	* @param  string      $regexp Regexp
80
	* @return array               Array of DOMNode instances
81
	*/
82
	public static function getElementsByRegexp(DOMDocument $dom, $regexp)
83
	{
84
		$xpath = new DOMXPath($dom);
85
		$nodes = [];
86
87
		// Get literal attributes
88
		foreach ($xpath->query('//*') as $element)
89
		{
90
			if (preg_match($regexp, $element->localName))
91
			{
92
				$nodes[] = $element;
93
			}
94
		}
95
96
		// Get generated elements
97
		foreach ($xpath->query('//xsl:element') as $element)
98
		{
99
			if (preg_match($regexp, $element->getAttribute('name')))
100
			{
101
				$nodes[] = $element;
102
			}
103
		}
104
105
		// Get elements created with <xsl:copy-of/>
106
		// NOTE: this method of creating elements is disallowed by default
107
		foreach ($xpath->query('//xsl:copy-of') as $node)
108
		{
109
			$expr = $node->getAttribute('select');
110
			if (preg_match('/^\\w+$/', $expr) && preg_match($regexp, $expr))
111
			{
112
				$nodes[] = $node;
113
			}
114
		}
115
116
		return $nodes;
117
	}
118
119
	/**
120
	* Return all DOMNodes whose content is JavaScript
121
	*
122
	* @param  DOMDocument $dom Document
123
	* @return array            Array of DOMNode instances
124
	*/
125
	public static function getJSNodes(DOMDocument $dom)
126
	{
127
		$regexp = '/^(?:data-s9e-livepreview-postprocess$|on)/i';
128
		$nodes  = array_merge(
129
			self::getAttributesByRegexp($dom, $regexp),
130
			self::getElementsByRegexp($dom, '/^script$/i')
131
		);
132
133
		return $nodes;
134
	}
135
136
	/**
137
	* Return all elements (literal or generated) that match given regexp
138
	*
139
	* Will return all <param/> descendants of <object/> and all attributes of <embed/> whose name
140
	* matches given regexp. This method will NOT catch <param/> elements whose 'name' attribute is
141
	* set via an <xsl:attribute/>
142
	*
143
	* @param  DOMDocument $dom    Document
144
	* @param  string      $regexp
145
	* @return array               Array of DOMNode instances
146
	*/
147
	public static function getObjectParamsByRegexp(DOMDocument $dom, $regexp)
148
	{
149
		$xpath = new DOMXPath($dom);
150
		$nodes = [];
151
152
		// Collect attributes from <embed/> elements
153
		foreach (self::getAttributesByRegexp($dom, $regexp) as $attribute)
154
		{
155
			if ($attribute->nodeType === XML_ATTRIBUTE_NODE)
156
			{
157
				if (strtolower($attribute->parentNode->localName) === 'embed')
158
				{
159
					$nodes[] = $attribute;
160
				}
161
			}
162
			elseif ($xpath->evaluate('ancestor::embed', $attribute))
163
			{
164
				// Assuming <xsl:attribute/> or <xsl:copy-of/>
165
				$nodes[] = $attribute;
166
			}
167
		}
168
169
		// Collect <param/> descendants of <object/> elements
170
		foreach ($dom->getElementsByTagName('object') as $object)
171
		{
172
			foreach ($object->getElementsByTagName('param') as $param)
173
			{
174
				if (preg_match($regexp, $param->getAttribute('name')))
175
				{
176
					$nodes[] = $param;
177
				}
178
			}
179
		}
180
181
		return $nodes;
182
	}
183
184
	/**
185
	* Return all DOMNodes whose content is an URL
186
	*
187
	* NOTE: it will also return HTML4 nodes whose content is an URI
188
	*
189
	* @param  DOMDocument $dom Document
190
	* @return array            Array of DOMNode instances
191
	*/
192
	public static function getURLNodes(DOMDocument $dom)
193
	{
194
		$regexp = '/(?:^(?:action|background|c(?:ite|lassid|odebase)|data|formaction|href|icon|longdesc|manifest|p(?:ing|luginspage|oster|rofile)|usemap)|src)$/i';
195
		$nodes  = self::getAttributesByRegexp($dom, $regexp);
196
197
		/**
198
		* @link http://helpx.adobe.com/flash/kb/object-tag-syntax-flash-professional.html
199
		* @link http://www.sitepoint.com/control-internet-explorer/
200
		*/
201
		foreach (self::getObjectParamsByRegexp($dom, '/^(?:dataurl|movie)$/i') as $param)
202
		{
203
			$node = $param->getAttributeNode('value');
204
			if ($node)
205
			{
206
				$nodes[] = $node;
207
			}
208
		}
209
210
		return $nodes;
211
	}
212
}