Parse a CSS selector into an associative array suitable for use with findNodes().
@since Method available since Release 3.3.0 @author Mike Naberezny <mike@maintainable.com> @author Derek DeVries <derek@maintainable.com>
string $selector:
mixed $content:
array
public static function convertSelectToTag($selector, $content = TRUE) {
$selector = trim(preg_replace("/\\s+/", " ", $selector));
// substitute spaces within attribute value
while (preg_match('/\\[[^\\]]+"[^"]+\\s[^"]+"\\]/', $selector)) {
$selector = preg_replace('/(\\[[^\\]]+"[^"]+)\\s([^"]+"\\])/', "\$1__SPACE__\$2", $selector);
}
if (strstr($selector, ' ')) {
$elements = explode(' ', $selector);
}
else {
$elements = array(
$selector,
);
}
$previousTag = array();
foreach (array_reverse($elements) as $element) {
$element = str_replace('__SPACE__', ' ', $element);
// child selector
if ($element == '>') {
$previousTag = array(
'child' => $previousTag['descendant'],
);
continue;
}
$tag = array();
// match element tag
preg_match("/^([^\\.#\\[]*)/", $element, $eltMatches);
if (!empty($eltMatches[1])) {
$tag['tag'] = $eltMatches[1];
}
// match attributes (\[[^\]]*\]*), ids (#[^\.#\[]*),
// and classes (\.[^\.#\[]*))
preg_match_all("/(\\[[^\\]]*\\]*|#[^\\.#\\[]*|\\.[^\\.#\\[]*)/", $element, $matches);
if (!empty($matches[1])) {
$classes = array();
$attrs = array();
foreach ($matches[1] as $match) {
// id matched
if (substr($match, 0, 1) == '#') {
$tag['id'] = substr($match, 1);
}
else {
if (substr($match, 0, 1) == '.') {
$classes[] = substr($match, 1);
}
else {
if (substr($match, 0, 1) == '[' && substr($match, -1, 1) == ']') {
$attribute = substr($match, 1, strlen($match) - 2);
$attribute = str_replace('"', '', $attribute);
// match single word
if (strstr($attribute, '~=')) {
list($key, $value) = explode('~=', $attribute);
$value = "regexp:/.*\\b{$value}\\b.*/";
}
else {
if (strstr($attribute, '*=')) {
list($key, $value) = explode('*=', $attribute);
$value = "regexp:/.*{$value}.*/";
}
else {
list($key, $value) = explode('=', $attribute);
}
}
$attrs[$key] = $value;
}
}
}
}
if ($classes) {
$tag['class'] = join(' ', $classes);
}
if ($attrs) {
$tag['attributes'] = $attrs;
}
}
// tag content
if (is_string($content)) {
$tag['content'] = $content;
}
// determine previous child/descendants
if (!empty($previousTag['descendant'])) {
$tag['descendant'] = $previousTag['descendant'];
}
else {
if (!empty($previousTag['child'])) {
$tag['child'] = $previousTag['child'];
}
}
$previousTag = array(
'descendant' => $tag,
);
}
return $tag;
}