Break a CSS file into an array with PHP

2019-01-24 11:14发布

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

4条回答
冷血范
2楼-- · 2019-01-24 11:56

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

查看更多
啃猪蹄的小仙女
3楼-- · 2019-01-24 12:01

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\,\.\:#_\-@]+)\{([^\}]*)\}/', $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{ ... }

查看更多
Viruses.
4楼-- · 2019-01-24 12:15

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.

查看更多
放荡不羁爱自由
5楼-- · 2019-01-24 12:18

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

查看更多
登录 后发表回答