Home » Php » Break a CSS file into an array with PHP

Break a CSS file into an array with PHP

Posted by: admin July 12, 2020 Leave a comment

Questions:

I wanted to break a css file into an array with PHP.

Ex:

#selector{ display:block; width:100px; }
#selector a{ float:left; text-decoration:none; }

Into a php array…

array(2) {
  ["#selector"] => array(2) {
    [0] => array(1) {
      ["display"] => string(5) "block"
    }
    [1] => array(1) {
      ["width"] => string(5) "100px"
    }
  }
  ["#selector a"] => array(2) {
    [0] => array(1) {
      ["float"] => string(4) "left"
    }
    [1] => array(1) {
      ["text-decoration"] => string(4) "none"
    }
  }
}

Any ideas?

Oh : Edit : I am not worried about ill formed CSS files in this instance. Doesn’t ahve to be bulletproof as long as its not greedy

How to&Answers:

This should do it:

<?php

$css = <<<CSS
#selector { display:block; width:100px; }
#selector a { float:left; text-decoration:none }
CSS;

//
function BreakCSS($css)
{

    $results = array();

    preg_match_all('/(.+?)\s?\{\s?(.+?)\s?\}/', $css, $matches);
    foreach($matches[0] AS $i=>$original)
        foreach(explode(';', $matches[2][$i]) AS $attr)
            if (strlen(trim($attr)) > 0) // for missing semicolon on last element, which is legal
            {
                list($name, $value) = explode(':', $attr);
                $results[$matches[1][$i]][trim($name)] = trim($value);
            }
    return $results;
}
var_dump(BreakCSS($css));

Quick Explanation: The regexp is simple and boring. It just matches all “anything, possible space, curly bracket, possible space, anything, close curly bracket”. From there, the first match is the selector, the second match is the attribute list. Split that by semicolons, and you’re left with key/value pairs. Some trim()’s in there to get rid of whitespace, and that’s about it.

I’m guessing that your next best bet would probably be to explode the selector by a comma so that you can consolidate attributes that apply to the same thing etc., but I’ll save that for you. 🙂

Edit: As mentioned above, a real grammar parser would be more practical… but if you’re assuming well-formed CSS, there’s no reason why you need to do anything beyond the simplest of “anything { anything }”. Depends on what you want to do with it, really.

Answer:

If you need the same for CSS rules with multi selectors and with breaklines:

<?php                      
$css = "
#selector
{ display:block; 
width:100px; 
}
#selector a:hover div.asd, #asd h1.asd { 
float:left; 
text-decoration:none; 
}
";
preg_match_all( '/(?ims)([a-z0-9\s\,\.\:#_\[email protected]]+)\{([^\}]*)\}/', $css, $arr);

$result = array();
foreach ($arr[0] as $i => $x)
{
    $selector = trim($arr[1][$i]);
    $rules = explode(';', trim($arr[2][$i]));
    $result[$selector] = array();
    foreach ($rules as $strRule)
    {
        if (!empty($strRule))
        {
            $rule = explode(":", $strRule);
            $result[$selector][][trim($rule[0])] = trim($rule[1]);
        }
    }
}   

var_dump($result);
?>

output:

array(2) {
  ["#selector"]=>
  array(2) {
    [0]=>
    array(1) {
      ["display"]=>
      string(5) "block"
    }
    [1]=>
    array(1) {
      ["width"]=>
      string(5) "100px"
    }
  }
  ["#selector a:hover div.asd, #asd h1.asd"]=>
  array(2) {
    [0]=>
    array(1) {
      ["float"]=>
      string(4) "left"
    }
    [1]=>
    array(1) {
      ["text-decoration"]=>
      string(4) "none"
    }
  }
}

Update: Added support for multiple selectors like: .box, .element, div{ … }

Answer:

If I were you, I would build (or find) a real grammar for CSS, and do parsing that way. Trying to write a parser for any non-trivial expression language (and CSS clearly isn’t trivial, with all the fancy selectors) have gotten me into trouble more than enough times.

Example: http://www.phpclasses.org/package/1289-PHP-CSS-parser-class.html

Answer:

I would suggest the selector (?ims)([a-z0-9\s\,\.\:#_\[email protected]*()\[\]"=]+)\{([^\}]*)\} in the answer of inakiabt for a better solution.