Search code examples
phpcssparsingcss-parsing

PHP CSS Parser - Selector Declarations to String


I want to be able to read a CSS file, and be able to extract all declarations of a given selector in to a string. For example, given the following stylesheet:

h1 {
  font-size: 15px;
  font-weight: bold;
  font-style: italic;
  font-family: Verdana, Arial, Helvetica, sans-serif;
}

div.item {
  font-size: 12px;
  border:1px solid #EEE;
}

I want to be able to call and get div.item, something like:

$css->getSelector('div.item');

Which should give me a string like:

font-size:12px;border:1px solid #EEE;

I have been looking around but can't find a parser that can do exactly that. Any ideas?

FYI: I need this to be able to convert selectors from a CSS and embed the styles dynamically in to HTML elements in email messages.

SOLUTION EDIT: I came up with my own crude solution and created a class to do what I was looking for. See my own answer below.


Solution

  • I came up with my own crude solution and created a class to do what I was looking for. My sources are referenced at the bottom.

    class css2string {
        var $css;
    
        function parseStr($string) {
            preg_match_all( '/(?ims)([a-z0-9, \s\.\:#_\-@]+)\{([^\}]*)\}/', $string, $arr);
            $this->css = array();
            foreach ($arr[0] as $i => $x)
            {
                $selector = trim($arr[1][$i]);
                $rules = explode(';', trim($arr[2][$i]));
                $this->css[$selector] = array();
                foreach ($rules as $strRule)
                {
                    if (!empty($strRule))
                    {
                        $rule = explode(":", $strRule);
                        $this->css[$selector][trim($rule[0])] = trim($rule[1]);
                    }
                }
            }
        }
    
        function arrayImplode($glue,$separator,$array) {
            if (!is_array($array)) return $array;
            $styleString = array();
            foreach ($array as $key => $val) {
                if (is_array($val))
                    $val = implode(',',$val);
                $styleString[] = "{$key}{$glue}{$val}";
    
            }
            return implode($separator,$styleString);   
        }
    
        function getSelector($selectorName) {
            return $this->arrayImplode(":",";",$this->css[$selectorName]);
        }
    
    }
    

    You can run it as follows:

    $cssString = "
    h1 {
      font-size: 15px;
      font-weight: bold;
      font-style: italic;
      font-family: Verdana, Arial, Helvetica, sans-serif;
    }
    
    div.item {
      font-size: 12px;
      border:1px solid #EEE;
    }";
    
    $getStyle = new css2string();
    $getStyle->parseStr(cssString);
    echo $getStyle->getSelector("div.item");
    

    The output would be as follows:

    font-size:12px;border:1px solid #EEE
    

    This solution works even with comments within your CSS file, as long as the comments are not inside selectors.

    References: http://www.php.net/manual/en/function.implode.php#106085 http://stackoverflow.com/questions/1215074/break-a-css-file-into-an-array-with-php