composer package updates
[openemr.git] / vendor / sabberworm / php-css-parser / README.md
blob48a95b2172fde3253a2c99c3d4f6838dffb0929f
1 PHP CSS Parser
2 --------------
4 [![build status](https://api.travis-ci.org/sabberworm/PHP-CSS-Parser.svg)](https://travis-ci.org/sabberworm/PHP-CSS-Parser) [![HHVM Status](http://hhvm.h4cc.de/badge/sabberworm/php-css-parser.svg)](http://hhvm.h4cc.de/package/sabberworm/php-css-parser)
6 A Parser for CSS Files written in PHP. Allows extraction of CSS files into a data structure, manipulation of said structure and output as (optimized) CSS.
8 ## Usage
10 ### Installation using composer
12 Add php-css-parser to your composer.json
14 ```json
16     "require": {
17         "sabberworm/php-css-parser": "*"
18     }
20 ```
22 ### Extraction
24 To use the CSS Parser, create a new instance. The constructor takes the following form:
26 ```php
27 new Sabberworm\CSS\Parser($sText);
28 ```
30 To read a file, for example, you’d do the following:
32 ```php
33 $oCssParser = new Sabberworm\CSS\Parser(file_get_contents('somefile.css'));
34 $oCssDocument = $oCssParser->parse();
35 ```
37 The resulting CSS document structure can be manipulated prior to being output.
39 ### Options
41 #### Charset
43 The charset option is used only if no @charset declaration is found in the CSS file. UTF-8 is the default, so you won’t have to create a settings object at all if you don’t intend to change that.
45 ```php
46 $oSettings = Sabberworm\CSS\Settings::create()->withDefaultCharset('windows-1252');
47 new Sabberworm\CSS\Parser($sText, $oSettings);
48 ```
50 #### Strict parsing
52 To have the parser choke on invalid rules, supply a thusly configured Sabberworm\CSS\Settings object:
54 ```php
55 $oCssParser = new Sabberworm\CSS\Parser(file_get_contents('somefile.css'), Sabberworm\CSS\Settings::create()->beStrict());
56 ```
58 #### Disable multibyte functions
60 To achieve faster parsing, you can choose to have PHP-CSS-Parser use regular string functions instead of `mb_*` functions. This should work fine in most cases, even for UTF-8 files, as all the multibyte characters are in string literals. Still it’s not recommended to use this with input you have no control over as it’s not thoroughly covered by test cases.
62 ```php
63 $oSettings = Sabberworm\CSS\Settings::create()->withMultibyteSupport(false);
64 new Sabberworm\CSS\Parser($sText, $oSettings);
65 ```
67 ### Manipulation
69 The resulting data structure consists mainly of five basic types: `CSSList`, `RuleSet`, `Rule`, `Selector` and `Value`. There are two additional types used: `Import` and `Charset` which you won’t use often.
71 #### CSSList
73 `CSSList` represents a generic CSS container, most likely containing declaration blocks (rule sets with a selector) but it may also contain at-rules, charset declarations, etc. `CSSList` has the following concrete subtypes:
75 * `Document` – representing the root of a CSS file.
76 * `MediaQuery` – represents a subsection of a CSSList that only applies to a output device matching the contained media query.
78 To access the items stored in a `CSSList` – like the document you got back when calling `$oCssParser->parse()` –, use `getContents()`, then iterate over that collection and use instanceof to check whether you’re dealing with another `CSSList`, a `RuleSet`, a `Import` or a `Charset`.
80 To append a new item (selector, media query, etc.) to an existing `CSSList`, construct it using the constructor for this class and use the `append($oItem)` method.
82 #### RuleSet
84 `RuleSet` is a container for individual rules. The most common form of a rule set is one constrained by a selector. The following concrete subtypes exist:
86 * `AtRuleSet` – for generic at-rules which do not match the ones specifically mentioned like @import, @charset or @media. A common example for this is @font-face.
87 * `DeclarationBlock` – a RuleSet constrained by a `Selector`; contains an array of selector objects (comma-separated in the CSS) as well as the rules to be applied to the matching elements.
89 Note: A `CSSList` can contain other `CSSList`s (and `Import`s as well as a `Charset`) while a `RuleSet` can only contain `Rule`s.
91 If you want to manipulate a `RuleSet`, use the methods `addRule(Rule $oRule)`, `getRules()` and `removeRule($mRule)` (which accepts either a Rule instance or a rule name; optionally suffixed by a dash to remove all related rules).
93 #### Rule
95 `Rule`s just have a key (the rule) and a value. These values are all instances of a `Value`.
97 #### Value
99 `Value` is an abstract class that only defines the `render` method. The concrete subclasses for atomic value types are:
101 * `Size` – consists of a numeric `size` value and a unit.
102 * `Color` – colors can be input in the form #rrggbb, #rgb or schema(val1, val2, …) but are always stored as an array of ('s' => val1, 'c' => val2, 'h' => val3, …) and output in the second form.
103 * `CSSString` – this is just a wrapper for quoted strings to distinguish them from keywords; always output with double quotes.
104 * `URL` – URLs in CSS; always output in URL("") notation.
106 There is another abstract subclass of `Value`, `ValueList`. A `ValueList` represents a lists of `Value`s, separated by some separation character (mostly `,`, whitespace, or `/`). There are two types of `ValueList`s:
108 * `RuleValueList` – The default type, used to represent all multi-valued rules like `font: bold 12px/3 Helvetica, Verdana, sans-serif;` (where the value would be a whitespace-separated list of the primitive value `bold`, a slash-separated list and a comma-separated list).
109 * `CSSFunction` – A special kind of value that also contains a function name and where the values are the function’s arguments. Also handles equals-sign-separated argument lists like `filter: alpha(opacity=90);`.
111 #### Convenience methods
113 There are a few convenience methods on Document to ease finding, manipulating and deleting rules:
115 * `getAllDeclarationBlocks()` – does what it says; no matter how deeply nested your selectors are. Aliased as `getAllSelectors()`.
116 * `getAllRuleSets()` – does what it says; no matter how deeply nested your rule sets are.
117 * `getAllValues()` – finds all `Value` objects inside `Rule`s.
119 ## To-Do
121 * More convenience methods [like `selectorsWithElement($sId/Class/TagName)`, `attributesOfType($sType)`, `removeAttributesOfType($sType)`]
122 * Real multibyte support. Currently only multibyte charsets whose first 255 code points take up only one byte and are identical with ASCII are supported (yes, UTF-8 fits this description).
123 * Named color support (using `Color` instead of an anonymous string literal)
125 ## Use cases
127 ### Use `Parser` to prepend an id to all selectors
129 ```php
130 $sMyId = "#my_id";
131 $oParser = new Sabberworm\CSS\Parser($sText);
132 $oCss = $oParser->parse();
133 foreach($oCss->getAllDeclarationBlocks() as $oBlock) {
134         foreach($oBlock->getSelectors() as $oSelector) {
135                 //Loop over all selector parts (the comma-separated strings in a selector) and prepend the id
136                 $oSelector->setSelector($sMyId.' '.$oSelector->getSelector());
137         }
141 ### Shrink all absolute sizes to half
143 ```php
144 $oParser = new Sabberworm\CSS\Parser($sText);
145 $oCss = $oParser->parse();
146 foreach($oCss->getAllValues() as $mValue) {
147         if($mValue instanceof CSSSize && !$mValue->isRelative()) {
148                 $mValue->setSize($mValue->getSize()/2);
149         }
153 ### Remove unwanted rules
155 ```php
156 $oParser = new Sabberworm\CSS\Parser($sText);
157 $oCss = $oParser->parse();
158 foreach($oCss->getAllRuleSets() as $oRuleSet) {
159         $oRuleSet->removeRule('font-'); //Note that the added dash will make this remove all rules starting with font- (like font-size, font-weight, etc.) as well as a potential font-rule
160         $oRuleSet->removeRule('cursor');
164 ### Output
166 To output the entire CSS document into a variable, just use `->render()`:
168 ```php
169 $oCssParser = new Sabberworm\CSS\Parser(file_get_contents('somefile.css'));
170 $oCssDocument = $oCssParser->parse();
171 print $oCssDocument->render();
174 If you want to format the output, pass an instance of type `Sabberworm\CSS\OutputFormat`:
176 ```php
177 $oFormat = Sabberworm\CSS\OutputFormat::create()->indentWithSpaces(4)->setSpaceBetweenRules("\n");
178 print $oCssDocument->render($oFormat);
181 Or use one of the predefined formats:
183 ```php
184 print $oCssDocument->render(Sabberworm\CSS\OutputFormat::createPretty());
185 print $oCssDocument->render(Sabberworm\CSS\OutputFormat::createCompact());
188 To see what you can do with output formatting, look at the tests in `tests/Sabberworm/CSS/OutputFormatTest.php`.
190 ## Examples
192 ### Example 1 (At-Rules)
194 #### Input
196 ```css
197 @charset "utf-8";
199 @font-face {
200   font-family: "CrassRoots";
201   src: url("../media/cr.ttf")
204 html, body {
205     font-size: 1.6em
208 @keyframes mymove {
209         from { top: 0px; }
210         to { top: 200px; }
215 #### Structure (`var_dump()`)
217 ```php
218 class Sabberworm\CSS\CSSList\Document#4 (2) {
219   protected $aContents =>
220   array(4) {
221     [0] =>
222     class Sabberworm\CSS\Property\Charset#6 (2) {
223       private $sCharset =>
224       class Sabberworm\CSS\Value\CSSString#5 (2) {
225         private $sString =>
226         string(5) "utf-8"
227         protected $iLineNo =>
228         int(1)
229       }
230       protected $iLineNo =>
231       int(1)
232     }
233     [1] =>
234     class Sabberworm\CSS\RuleSet\AtRuleSet#7 (4) {
235       private $sType =>
236       string(9) "font-face"
237       private $sArgs =>
238       string(0) ""
239       private $aRules =>
240       array(2) {
241         'font-family' =>
242         array(1) {
243           [0] =>
244           class Sabberworm\CSS\Rule\Rule#8 (4) {
245             private $sRule =>
246             string(11) "font-family"
247             private $mValue =>
248             class Sabberworm\CSS\Value\CSSString#9 (2) {
249               private $sString =>
250               string(10) "CrassRoots"
251               protected $iLineNo =>
252               int(4)
253             }
254             private $bIsImportant =>
255             bool(false)
256             protected $iLineNo =>
257             int(4)
258           }
259         }
260         'src' =>
261         array(1) {
262           [0] =>
263           class Sabberworm\CSS\Rule\Rule#10 (4) {
264             private $sRule =>
265             string(3) "src"
266             private $mValue =>
267             class Sabberworm\CSS\Value\URL#11 (2) {
268               private $oURL =>
269               class Sabberworm\CSS\Value\CSSString#12 (2) {
270                 private $sString =>
271                 string(15) "../media/cr.ttf"
272                 protected $iLineNo =>
273                 int(5)
274               }
275               protected $iLineNo =>
276               int(5)
277             }
278             private $bIsImportant =>
279             bool(false)
280             protected $iLineNo =>
281             int(5)
282           }
283         }
284       }
285       protected $iLineNo =>
286       int(3)
287     }
288     [2] =>
289     class Sabberworm\CSS\RuleSet\DeclarationBlock#13 (3) {
290       private $aSelectors =>
291       array(2) {
292         [0] =>
293         class Sabberworm\CSS\Property\Selector#14 (2) {
294           private $sSelector =>
295           string(4) "html"
296           private $iSpecificity =>
297           NULL
298         }
299         [1] =>
300         class Sabberworm\CSS\Property\Selector#15 (2) {
301           private $sSelector =>
302           string(4) "body"
303           private $iSpecificity =>
304           NULL
305         }
306       }
307       private $aRules =>
308       array(1) {
309         'font-size' =>
310         array(1) {
311           [0] =>
312           class Sabberworm\CSS\Rule\Rule#16 (4) {
313             private $sRule =>
314             string(9) "font-size"
315             private $mValue =>
316             class Sabberworm\CSS\Value\Size#17 (4) {
317               private $fSize =>
318               double(1.6)
319               private $sUnit =>
320               string(2) "em"
321               private $bIsColorComponent =>
322               bool(false)
323               protected $iLineNo =>
324               int(9)
325             }
326             private $bIsImportant =>
327             bool(false)
328             protected $iLineNo =>
329             int(9)
330           }
331         }
332       }
333       protected $iLineNo =>
334       int(8)
335     }
336     [3] =>
337     class Sabberworm\CSS\CSSList\KeyFrame#18 (4) {
338       private $vendorKeyFrame =>
339       string(9) "keyframes"
340       private $animationName =>
341       string(6) "mymove"
342       protected $aContents =>
343       array(2) {
344         [0] =>
345         class Sabberworm\CSS\RuleSet\DeclarationBlock#19 (3) {
346           private $aSelectors =>
347           array(1) {
348             [0] =>
349             class Sabberworm\CSS\Property\Selector#20 (2) {
350               private $sSelector =>
351               string(4) "from"
352               private $iSpecificity =>
353               NULL
354             }
355           }
356           private $aRules =>
357           array(1) {
358             'top' =>
359             array(1) {
360               [0] =>
361               class Sabberworm\CSS\Rule\Rule#21 (4) {
362                 private $sRule =>
363                 string(3) "top"
364                 private $mValue =>
365                 class Sabberworm\CSS\Value\Size#22 (4) {
366                   private $fSize =>
367                   double(0)
368                   private $sUnit =>
369                   string(2) "px"
370                   private $bIsColorComponent =>
371                   bool(false)
372                   protected $iLineNo =>
373                   int(13)
374                 }
375                 private $bIsImportant =>
376                 bool(false)
377                 protected $iLineNo =>
378                 int(13)
379               }
380             }
381           }
382           protected $iLineNo =>
383           int(13)
384         }
385         [1] =>
386         class Sabberworm\CSS\RuleSet\DeclarationBlock#23 (3) {
387           private $aSelectors =>
388           array(1) {
389             [0] =>
390             class Sabberworm\CSS\Property\Selector#24 (2) {
391               private $sSelector =>
392               string(2) "to"
393               private $iSpecificity =>
394               NULL
395             }
396           }
397           private $aRules =>
398           array(1) {
399             'top' =>
400             array(1) {
401               [0] =>
402               class Sabberworm\CSS\Rule\Rule#25 (4) {
403                 private $sRule =>
404                 string(3) "top"
405                 private $mValue =>
406                 class Sabberworm\CSS\Value\Size#26 (4) {
407                   private $fSize =>
408                   double(200)
409                   private $sUnit =>
410                   string(2) "px"
411                   private $bIsColorComponent =>
412                   bool(false)
413                   protected $iLineNo =>
414                   int(14)
415                 }
416                 private $bIsImportant =>
417                 bool(false)
418                 protected $iLineNo =>
419                 int(14)
420               }
421             }
422           }
423           protected $iLineNo =>
424           int(14)
425         }
426       }
427       protected $iLineNo =>
428       int(12)
429     }
430   }
431   protected $iLineNo =>
432   int(1)
437 #### Output (`render()`)
439 ```css
440 @charset "utf-8";
441 @font-face {font-family: "CrassRoots";src: url("../media/cr.ttf");}
442 html, body {font-size: 1.6em;}
443 @keyframes mymove {from {top: 0px;}
444         to {top: 200px;}}
447 ### Example 2 (Values)
449 #### Input
451 ```css
452 #header {
453         margin: 10px 2em 1cm 2%;
454         font-family: Verdana, Helvetica, "Gill Sans", sans-serif;
455         color: red !important;
460 #### Structure (`var_dump()`)
462 ```php
463 class Sabberworm\CSS\CSSList\Document#4 (2) {
464   protected $aContents =>
465   array(1) {
466     [0] =>
467     class Sabberworm\CSS\RuleSet\DeclarationBlock#5 (3) {
468       private $aSelectors =>
469       array(1) {
470         [0] =>
471         class Sabberworm\CSS\Property\Selector#6 (2) {
472           private $sSelector =>
473           string(7) "#header"
474           private $iSpecificity =>
475           NULL
476         }
477       }
478       private $aRules =>
479       array(3) {
480         'margin' =>
481         array(1) {
482           [0] =>
483           class Sabberworm\CSS\Rule\Rule#7 (4) {
484             private $sRule =>
485             string(6) "margin"
486             private $mValue =>
487             class Sabberworm\CSS\Value\RuleValueList#12 (3) {
488               protected $aComponents =>
489               array(4) {
490                 [0] =>
491                 class Sabberworm\CSS\Value\Size#8 (4) {
492                   private $fSize =>
493                   double(10)
494                   private $sUnit =>
495                   string(2) "px"
496                   private $bIsColorComponent =>
497                   bool(false)
498                   protected $iLineNo =>
499                   int(2)
500                 }
501                 [1] =>
502                 class Sabberworm\CSS\Value\Size#9 (4) {
503                   private $fSize =>
504                   double(2)
505                   private $sUnit =>
506                   string(2) "em"
507                   private $bIsColorComponent =>
508                   bool(false)
509                   protected $iLineNo =>
510                   int(2)
511                 }
512                 [2] =>
513                 class Sabberworm\CSS\Value\Size#10 (4) {
514                   private $fSize =>
515                   double(1)
516                   private $sUnit =>
517                   string(2) "cm"
518                   private $bIsColorComponent =>
519                   bool(false)
520                   protected $iLineNo =>
521                   int(2)
522                 }
523                 [3] =>
524                 class Sabberworm\CSS\Value\Size#11 (4) {
525                   private $fSize =>
526                   double(2)
527                   private $sUnit =>
528                   string(1) "%"
529                   private $bIsColorComponent =>
530                   bool(false)
531                   protected $iLineNo =>
532                   int(2)
533                 }
534               }
535               protected $sSeparator =>
536               string(1) " "
537               protected $iLineNo =>
538               int(2)
539             }
540             private $bIsImportant =>
541             bool(false)
542             protected $iLineNo =>
543             int(2)
544           }
545         }
546         'font-family' =>
547         array(1) {
548           [0] =>
549           class Sabberworm\CSS\Rule\Rule#13 (4) {
550             private $sRule =>
551             string(11) "font-family"
552             private $mValue =>
553             class Sabberworm\CSS\Value\RuleValueList#15 (3) {
554               protected $aComponents =>
555               array(4) {
556                 [0] =>
557                 string(7) "Verdana"
558                 [1] =>
559                 string(9) "Helvetica"
560                 [2] =>
561                 class Sabberworm\CSS\Value\CSSString#14 (2) {
562                   private $sString =>
563                   string(9) "Gill Sans"
564                   protected $iLineNo =>
565                   int(3)
566                 }
567                 [3] =>
568                 string(10) "sans-serif"
569               }
570               protected $sSeparator =>
571               string(1) ","
572               protected $iLineNo =>
573               int(3)
574             }
575             private $bIsImportant =>
576             bool(false)
577             protected $iLineNo =>
578             int(3)
579           }
580         }
581         'color' =>
582         array(1) {
583           [0] =>
584           class Sabberworm\CSS\Rule\Rule#16 (4) {
585             private $sRule =>
586             string(5) "color"
587             private $mValue =>
588             string(3) "red"
589             private $bIsImportant =>
590             bool(true)
591             protected $iLineNo =>
592             int(4)
593           }
594         }
595       }
596       protected $iLineNo =>
597       int(1)
598     }
599   }
600   protected $iLineNo =>
601   int(1)
606 #### Output (`render()`)
608 ```css
609 #header {margin: 10px 2em 1cm 2%;font-family: Verdana,Helvetica,"Gill Sans",sans-serif;color: red !important;}
612 ## Contributors/Thanks to
614 * [FMCorz](https://github.com/FMCorz) for many patches and suggestions, for being able to parse comments and IE hacks (in lenient mode).
615 * [Lullabot](https://github.com/Lullabot) for a patch that allows to know the line number for each parsed token.
616 * [ju1ius](https://github.com/ju1ius) for the specificity parsing code and the ability to expand/compact shorthand properties.
617 * [ossinkine](https://github.com/ossinkine) for a 150 time performance boost.
618 * [GaryJones](https://github.com/GaryJones) for lots of input and [http://css-specificity.info/](http://css-specificity.info/).
619 * [docteurklein](https://github.com/docteurklein) for output formatting and `CSSList->remove()` inspiration.
620 * [nicolopignatelli](https://github.com/nicolopignatelli) for PSR-0 compatibility.
621 * [diegoembarcadero](https://github.com/diegoembarcadero) for keyframe at-rule parsing.
622 * [goetas](https://github.com/goetas) for @namespace at-rule support.
623 * [View full list](https://github.com/sabberworm/PHP-CSS-Parser/contributors)
625 ## Misc
627 * Legacy Support: The latest pre-PSR-0 version of this project can be checked with the `0.9.0` tag.
628 * Running Tests: To run all unit tests for this project, have `phpunit` installed and run `phpunit .`.
630 ## License
632 PHP-CSS-Parser is freely distributable under the terms of an MIT-style license.
634 Copyright (c) 2011 Raphael Schweikert, http://sabberworm.com/
636 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
638 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
640 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.