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

InlineInferredValues   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 90
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 11
lcom 1
cbo 3
dl 0
loc 90
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A normalizeElement() 0 13 4
A inlineInferredValue() 0 16 3
A replaceAttribute() 0 17 3
A replaceValueOf() 0 7 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 DOMElement;
12
use DOMNode;
13
use s9e\TextFormatter\Configurator\Helpers\AVTHelper;
14
use s9e\TextFormatter\Configurator\Helpers\TemplateParser;
15
16
/**
17
* Inline the text content of a node or the value of an attribute where it's known
18
*
19
* Will replace
20
*     <xsl:if test="@foo='Foo'"><xsl:value-of select="@foo"/></xsl:if>
21
* with
22
*     <xsl:if test="@foo='Foo'">Foo</xsl:if>
23
*
24
* This should be applied after control structures have been optimized
25
*/
26
class InlineInferredValues extends AbstractNormalization
27
{
28
	/**
29
	* {@inheritdoc}
30
	*/
31
	protected $queries = ['//xsl:if', '//xsl:when'];
32
33
	/**
34
	* {@inheritdoc}
35
	*/
36
	protected function normalizeElement(DOMElement $element)
37
	{
38
		// Test whether the map has exactly one key and one value
39
		$map = TemplateParser::parseEqualityExpr($element->getAttribute('test'));
40
		if ($map === false || count($map) !== 1 || count($map[key($map)]) !== 1)
41
		{
42
			return;
43
		}
44
45
		$expr  = key($map);
46
		$value = end($map[$expr]);
47
		$this->inlineInferredValue($element, $expr, $value);
48
	}
49
50
	/**
51
	* Replace the inferred value in given node and its descendants
52
	*
53
	* @param  DOMNode $node  Context node
54
	* @param  string  $expr  XPath expression
55
	* @param  string  $value Inferred value
56
	* @return void
57
	*/
58
	protected function inlineInferredValue(DOMNode $node, $expr, $value)
59
	{
60
		// Get xsl:value-of descendants that match the condition
61
		$query = './/xsl:value-of[@select="' . $expr . '"]';
62
		foreach ($this->xpath($query, $node) as $valueOf)
63
		{
64
			$this->replaceValueOf($valueOf, $value);
65
		}
66
67
		// Get all attributes from non-XSL elements that *could* match the condition
68
		$query = './/*[namespace-uri() != $XSL]/@*[contains(., "{' . $expr . '}")]';
69
		foreach ($this->xpath($query, $node) as $attribute)
70
		{
71
			$this->replaceAttribute($attribute, $expr, $value);
72
		}
73
	}
74
75
	/**
76
	* Replace an expression with a literal value in given attribute
77
	*
78
	* @param  DOMAttr $attribute
79
	* @param  string  $expr
80
	* @param  string  $value
81
	* @return void
82
	*/
83
	protected function replaceAttribute(DOMAttr $attribute, $expr, $value)
84
	{
85
		AVTHelper::replace(
86
			$attribute,
87
			function ($token) use ($expr, $value)
88
			{
89
				// Test whether this expression is the one we're looking for
90
				if ($token[0] === 'expression' && $token[1] === $expr)
91
				{
92
					// Replace the expression with the value (as a literal)
93
					$token = ['literal', $value];
94
				}
95
96
				return $token;
97
			}
98
		);
99
	}
100
101
	/**
102
	* Replace an xsl:value-of element with a literal value
103
	*
104
	* @param  DOMElement $valueOf
105
	* @param  string     $value
106
	* @return void
107
	*/
108
	protected function replaceValueOf(DOMElement $valueOf, $value)
109
	{
110
		$valueOf->parentNode->replaceChild(
111
			$valueOf->ownerDocument->createTextNode($value),
112
			$valueOf
113
		);
114
	}
115
}