Completed
Push — master ( a22897...37985f )
by Richard
02:32
created

CssToXpath::compare()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 3
eloc 3
nc 3
nop 3
1
<?php
2
/* @description     Transformation Style Sheets - Revolutionising PHP templating    *
3
 * @author          Tom Butler [email protected]                                             *
4
 * @copyright       2015 Tom Butler <[email protected]> | https://r.je/                      *
5
 * @license         http://www.opensource.org/licenses/bsd-license.php  BSD License *
6
 * @version         1.0                                                             */
7
namespace Transphporm\Parser;
8
class CssToXpath {
9
	private $specialChars = [' ', '.', '>', '~', '#', ':', '[', ']'];
10
	private $translators = [];
11
	private $css;
12
	private $valueParser;
13
	private static $instances = [];
14
	private $functionSet;
15
16
17
	public function __construct(Value $valueParser, \Transphporm\FunctionSet $functionSet, $prefix = '') {
18
		$hash = $this->registerInstance();
19
		$this->valueParser = $valueParser;
20
		$this->functionSet = $functionSet;
21
22
		$this->translators = [
23
			' ' => function($string) use ($prefix) { return '//' . $prefix . $string;	},
24
			'' => function($string) use ($prefix) { return '/' . $prefix . $string;	},
25
			'>' => function($string) use ($prefix) { return '/' . $prefix  . $string; },
26
			'#' => function($string) { return '[@id=\'' . $string . '\']'; },
27
			'.' => function($string) { return '[contains(concat(\' \', normalize-space(@class), \' \'), \' ' . $string . ' \')]'; },
28
			'[' => function($string) use ($hash) { return '[' .'php:function(\'\Transphporm\Parser\CssToXpath::processAttr\', \'' . $string . '\', ., "' . $hash . '")' . ']';	},
29
			']' => function() {	return ''; }
30
		];
31
	}
32
33
	private function registerInstance() {
34
		$hash = spl_object_hash($this);
35
		self::$instances[$hash] = $this;
36
		return $hash;
37
	}
38
39
	private function createSelector() {
40
		$selector = new \stdclass;
41
		$selector->type = '';
42
		$selector->string = '';
43
		return $selector;
44
	}
45
46
	//XPath only allows registering of static functions... this is a hacky workaround for that
47
	public static function processAttr($attr, $element, $hash) {
48
		$comparators = ['!=', '='];
49
		$valueParser = self::$instances[$hash]->valueParser;
50
		self::$instances[$hash]->functionSet->setElement($element[0]);
51
52
		foreach ($comparators as $comparator) {
53
			if (strpos($attr, $comparator) !== false) {
54
				$parts = explode($comparator, $attr);
55
56
				return $valueParser->parse('attr(' . $parts[0] . ')' . $comparator . $parts[1])[0];
57
			}
58
		}
59
		return $element[0]->getAttribute($attr) !== '';
60
	}
61
62
	//split the css into indivudal functions
63
	private function split($css) {
64
		$selectors = [];
65
		$selector = $this->createSelector();
66
		$selectors[] = $selector;
67
68
		for ($i = 0; $i < strlen($css); $i++) {
69
			if (in_array($css[$i], $this->specialChars)) {
70
				$selector = $this->createSelector();
71
				$selector->type = $css[$i];
72
				$selectors[] = $selector;
73
			}
74
			else $selector->string .= $css[$i];
75
		}
76
		return $selectors;
77
	}
78
79
	public function getXpath($css) {
80
		$this->css = str_replace([' >', '> '],['>', '>'], trim($css));
81
		$css = explode(':', $this->css)[0];
82
		$selectors = $this->split($css);
83
		$xpath = '/';
84
		foreach ($selectors as $selector) {
85
			if (isset($this->translators[$selector->type])) $xpath .= $this->translators[$selector->type]($selector->string, $xpath);
86
		}
87
88
		$xpath = str_replace('/[', '/*[', $xpath);
89
90
		return $xpath;
91
	}
92
93
	public function getDepth($css) {
94
		return count($this->split($css));
95
	}
96
97
	public function getPseudo($css) {
98
		$parts = explode(':', $css);
99
		array_shift($parts);
100
		return $parts;
101
	}
102
}
103