Scripts

CSS Parser (ECSS)

Ik heb een documentatie geschreven van mij CSS Parser op http://www.ruudverbij.nl/css/documentation.doc Hierop is (in het engels) te vinden hoe mijn parser te gebruiken is. Kort kan ik zeggen dat je nu gebruik kunt maken van; -variabelen -commentaar deleten -pre-gedefineerde classes extenden Dit is echt een zeeer alpha versie, alles werkt (volgens mij) wel, maar het is nog erg basic. Toch wilde ik het vast met jullie delen! Het voorbeeld is een geparste versie van http://www.ruudverbij.nl/css/style.txt Vergeet niet dat er ook een .htaccess nodig is, en wat kleine notes zijn voor je het kunt gebruiken, vergeet aub niet om even de documentatie te lezen!

css-parser-ecss
[code]<?php

/** CSS parser class
  * used to parse normal css
  * @author 		Ruud Verbij
  * @start_date 	4 Oct 2007
  * @version 	    0.1a
  * @documentation	www.ruudverbij.nl/css/documentation.doc (very little)
  */

class CSSParser {

    // Class instance variables
    /*  Array with names of the css files to be parsed
      * initiated by the constructor and files added by addCSSFile()
      * @invariant cssNames != null && count(cssNames) > 0
      */
    private $cssNames = Array();

    /*  Array with content of the css files to be parsed (raw)
      * iniated by the constructor and updated by addCSSFile()
      * @invariant cssContents != null && count(cssContents) > 0
      */
    private $cssContents = Array();

    /*  Boolean that says if the output should be combined
      * if set true; setCombinedFileName() should be called
      * iniated by the constructor or updated by setCombinedFileName()
      * @invariant if(combined) getCombinedFileName != null
      */
    private $combine;

    /*  String containing the filename for the output if combine is set true
      * @invariant if(getCombined() == true) combinedFileName != null
      */
    private $combinedFileName = null;

    /*  Boolean that says if the parser should delete comments
      * initiated by the constructor and updated by cutComments()
      */
    private $cutComments;


    // Class constructor
    /** Constructor used for getting an instance of this class
      * @param Array - contains all files to be parsed (numeric)
      * @param Boolean - says if the fileoutput should be combined
      * @param Boolean - says if the parser should cut out comments
      * @require setCombinedFileName() must be called if combine is set true
      * @require count(files) > 0
      * @require file_exists(each file from $files)
      * @ensure getFileNames() == files
      * @ensure getCombined() == combine
      */
    public function __construct($files,$combine = false, $cutComments = true) {
        // set all instance variables
        $this->cssNames    = $files;
        $this->combine     = $combine;
        $this->cutComments = $cutComments;

        // get content from filenames and place them in the instance variable
        for($i = 0; $i < count($this->getFileNames()); $i++) {
            $this->cssContents[$i] = file_get_contents($this->cssNames[$i]);
        }
    }


    // Query functions
    /** function to check if combined has been set true
      * @return Boolean
      */
    public function getCombined() {
        return $this->combine;
    }

    /** function to check the filename of the combinedFileName
      * @return String or NULL
      */
    public function getCombinedFileName() {
        return $this->combinedFileName;
    }

    /** function to get all filenames that will be parsed
      * @return Array
      */
    public function getFileNames() {
        return $this->cssNames;
    }

    /** function to check if the parser will cut out comments
      * @return Boolean
      */
    public function getCutComments() {
        return $this->cutComments;
    }


    // Command functions
    /** function to set the combinedFileName
      * @param String
      * @ensure getCombined() == true
      * @ensure getCombinedFileName() == $filename
      */
    public function setCombinedFileName($filename) {
        $this->combine = true;
        $this->combinedFileName = (substr($filename,strlen($filename)-3) == 'css') ? substr($filename,0,strlen($filename)-1) : $filename;
    }

    /** function to add a cssfile that needs to be parsed
      * @param String
      * @ensure getFileNames()[i] == $filename
      */
    public function addCSSFile($filename) {
        $this->cssNames[] = $filename;
        $this->cssContents[] = file_get_contents($filename);
    }

    /** function to set the parser to cut comments or not
      * @param Boolean
      */
    public function setCutComments($cutComments) {
        $this->cutComments = $cutComments;
    }


    // Class functions
    /** function to parse the files added by addCSSFile and the constructor
      * @ensure if(getCombined()) then getCombinedFileName() contains all parsed css
      *         else getFileNames()[i] contains parsed css for file_get_contents(getFileNames()[i])
      */
    public function parseFiles() {
        $this->writeOutput($this->parse());
    }
    
    /*  function to write all output
      * @param Array - containing arrays per file (numeric) and per file (characters) 'css' and 'filename'
      * @ensure files will be written
      */
    private function writeOutput($output) {
        // then you can combine them
        if($this->getCombined()) {
            // combine all css
            $sub_output;
            for($i = 0; $i < count($output); $i++) {
                $sub_output .= '\n' . $output[$i]['css'];
            }

            // write sub_output to the getCombinedFileName() and build the file if it does not exists
            $handle = fopen($this->getCombinedFileName(), 'w');
            fwrite($handle, $sub_output);
            fclose($handle);
        } else {
            // write output to each file
            for($i = 0; $i < count($output); $i++) {
                $handle = fopen($output[$i]['filename'], 'w');
                fwrite($handle, $output[$i]['css']);
                fclose($handle);
            }
        }
    }
    
    /** echo the parsed files */
    public function echoParsedFiles() {
        $output = $this->parse();
        $sub_output;
        for($i = 0; $i < count($output); $i++) {
            $sub_output .= $output[$i]['css'];
        }
        echo $sub_output;
    }
    
    /* parse the filenames as prepared */
    private function parse() {
        $output = array();

        // first parse all files seperate
        for($i = 0; $i < count($this->getFileNames()); $i++) {
            $filenames = $this->getFileNames();
            $contents  = $this->cssContents[$i];
            $css = $this->splitFile($contents);
            $sub_output = ($this->getCutComments()) ? $this->cutComments($css[1]) : $css[1];
            $sub_output = $this->extendClasses($css[0],$sub_output);
            $sub_output = $this->parseVariables($css[0],$sub_output);
            $output[] = array('css'=> $sub_output,'filename'=>substr($filenames[$i],0,strlen($filenames[$i])-1));
        }
        
        return $output;
    }

    /*  function to split the file in 2 parts: the extended part and the actual css part
      * @param String - file to be split
      * @require $file != null
      * @return Array - return[0] = extended, return[1] = actual
    */
    static private function splitFile($file) {
        $filebrokencontent = preg_split('/\*\*\*[\s]?(ACTUAL|EXTENDED)[\s]?CSS[\s]?\*\*\*/i',$file);
        return array($filebrokencontent[1],$filebrokencontent[2]);
    }

    /*  function to cut out comments
      * @param String - containing the actual-part of the css file where comments should be cut out
      * @require $actual != null
      * @ensure return does not contain css-comments
      * @return String - the actual-css part without comments
      */
    static private function cutComments($actual) {
        return preg_replace('/\/\\*.*\*\//s','',$actual);
    }

    /*  function to parse variables declared in the extended part within the actual part
      * @param String - the extended part of the css
      * @param String - the actual part of the css
      * @require ($extended && $actual) != null
      * @return String - the actual part of the css file parsed with the variables declared in the extended part
      */
    static private function parseVariables($extended,$actual) {
        preg_match_all('/(\$[a-zA-Z]+[a-zA-Z0-9_]*)[\s]*:[\s]*([#0-9a-zA-Z\']+)/',$extended,$matches);
        $variables = $matches[1];
        $variables_content = $matches[2];
        for($i = 0; $i < count($variables); $i++)
            $actual = preg_replace('/\\'.$variables[$i].'/i',$variables_content[$i],$actual);
        return $actual;
    }

    /*  function to extend classes in the actual part with classes from the extended part
      * @param String - the extended part of the css
      * @param String - the actual part of the css
      * @require ($extended && $actual) != null
      * @return String - the actual part of the css file extended by the classes in the extended part
      */
    static private function extendClasses($extended,$actual) {
        preg_match_all('/([\.|#][a-zA-Z_]+)[\s]*{[\s]*([^}.]*)[\s]*}/s',$extended,$matches);
        $classes = $matches[1];
        $classes_style = $matches[2];
        for($i = 0; $i < count($classes); $i++)
           $actual = preg_replace('/extend-from: \''.$classes[$i].'\';/i',$classes_style[$i],$actual);
        $actual = preg_replace('/extended-from:[\s]*;/i','',$actual);
        return $actual;
    }
}

$file = $_GET['file'];
if(preg_match('/([a-zA-Z]+\.css)/',$file,$match)) {
    $cssparser = new CSSParser(array($file));
    $cssparser->parseFiles();
    echo file_get_contents(substr($file,0,strlen($file)-1));
}

?>[/code]

Reacties

0
Nog geen reacties.