prestashop/php-css-parser

此包已被废弃且不再维护。未建议替代包。

用PHP编写的CSS文件解析器

8.2.0 2017-12-28 13:36 UTC

README

build status HHVM Status

PHP编写的CSS文件解析器。允许将CSS文件提取到数据结构中,操作此结构并输出为(优化后的)CSS。

用法

使用Composer安装

将php-css-parser添加到composer.json中

{
    "require": {
        "sabberworm/php-css-parser": "*"
    }
}

提取

要使用CSS解析器,创建一个新的实例。构造函数采用以下形式

new Sabberworm\CSS\Parser($sText);

例如,要读取文件,可以这样做

$oCssParser = new Sabberworm\CSS\Parser(file_get_contents('somefile.css'));
$oCssDocument = $oCssParser->parse();

在输出之前,可以操作生成的CSS文档结构。

选项

字符集

只有在CSS文件中没有找到@charset声明时,才使用charset选项。UTF-8是默认值,所以如果您不打算更改该值,则无需创建设置对象。

$oSettings = Sabberworm\CSS\Settings::create()->withDefaultCharset('windows-1252');
new Sabberworm\CSS\Parser($sText, $oSettings);

严格解析

要使解析器对无效规则产生错误,请提供以下配置的Sabberworm\CSS\Settings对象

$oCssParser = new Sabberworm\CSS\Parser(file_get_contents('somefile.css'), Sabberworm\CSS\Settings::create()->beStrict());

禁用多字节函数

为了获得更快的解析速度,您可以选择让PHP-CSS-Parser使用常规字符串函数而不是mb_*函数。在大多数情况下,这应该没问题,即使是UTF-8文件,因为所有多字节字符都在字符串字面量中。但是,不建议您使用您无法控制的输入,因为它们没有经过充分的测试案例覆盖。

$oSettings = Sabberworm\CSS\Settings::create()->withMultibyteSupport(false);
new Sabberworm\CSS\Parser($sText, $oSettings);

操作

生成的数据结构主要由五种基本类型组成:CSSListRuleSetRuleSelectorValue。还有两种额外的类型被使用:ImportCharset,您不太经常使用。

CSSList

CSSList代表一个通用的CSS容器,最可能包含声明块(具有选择器的规则集),但它也可能包含@规则、字符集声明等。CSSList有以下具体子类型

  • Document – 代表CSS文件的根。
  • MediaQuery – 代表CSSList的一个子部分,仅适用于匹配包含媒体查询的输出设备。

要访问存储在CSSList中的项(例如,在调用$oCssParser->parse()时返回的文档),请使用getContents(),然后遍历该集合,并使用instanceof检查您是否正在处理另一个CSSListRuleSetImportCharset

要将新项(选择器、媒体查询等)追加到现有的CSSList中,请使用该类的构造函数构建它,并使用append($oItem)方法。

规则集

规则集 是单个规则的容器。规则集最常见的形式是由选择器约束的。以下是一些具体的子类型:

  • AtRuleSet – 用于通用的 at 规则,不匹配特定提到的规则,如 @import、@charset 或 @media。一个常见的例子是 @font-face。
  • DeclarationBlock – 一个由 选择器 约束的规则集;包含一个选择器对象数组(在 CSS 中以逗号分隔)以及应用于匹配元素的规则。

注意:一个 CSSList 可以包含其他 CSSList(以及 ImportCharset),而一个 RuleSet 只能包含 Rule

如果您想操作一个 RuleSet,请使用方法 addRule(Rule $oRule)getRules()removeRule($mRule)(它接受一个 Rule 实例或规则名;可选地以连字符结尾以删除所有相关规则)。

规则

规则 只有一个键(规则)和一个值。这些值都是 Value 的实例。

是一个抽象类,仅定义了 render 方法。原子值类型的具体子类包括:

  • Size – 由一个数字 size 值和一个单位组成。
  • Color – 颜色可以以 #rrggbb、#rgb 或 schema(val1, val2, …) 的形式输入,但总是存储为 ('s' => val1, 'c' => val2, 'h' => val3, …) 的数组,并以第二种形式输出。
  • CSSString – 这只是一个用于区分关键字和引号字符串的包装器;始终以双引号输出。
  • URL – CSS 中的 URL;始终以 URL("") 符号输出。

还有一个 Value 的抽象子类,ValueList。一个 ValueList 表示由一些分隔字符(通常是 ,、空白字符或 /)分隔的 Value 列表。有两种类型的 ValueList

  • RuleValueList – 默认类型,用于表示所有多值规则,如 font: bold 12px/3 Helvetica, Verdana, sans-serif;(其中值将是一个由空白字符分隔的原始值 bold 的列表、一个由斜杠分隔的列表和一个由逗号分隔的列表)。
  • CSSFunction – 一种包含函数名和值的特殊类型的值,其中值是函数的参数。也处理等于号分隔的参数列表,如 filter: alpha(opacity=90);

便利方法

在 Document 上有一些便利方法,可以简化查找、操作和删除规则

  • getAllDeclarationBlocks() – 做它所说的事情;无论您的选择器多么深嵌套。别名 getAllSelectors()
  • getAllRuleSets() – 做它所说的事情;无论您的规则集多么深嵌套。
  • getAllValues() – 在规则中查找所有 Value 对象。

待办事项

  • 更多的便利方法[如 selectorsWithElement($sId/Class/TagName)attributesOfType($sType)removeAttributesOfType($sType)]
  • 真正的多字节支持。目前只支持那些前 255 个代码点只占用一个字节且与 ASCII 相同的多字节字符集(是的,UTF-8 符合这个描述)。
  • 命名颜色支持(使用 Color 而不是匿名字符串字面量)

用例

使用 Parser 将 id 预先添加到所有选择器中

$sMyId = "#my_id";
$oParser = new Sabberworm\CSS\Parser($sText);
$oCss = $oParser->parse();
foreach($oCss->getAllDeclarationBlocks() as $oBlock) {
	foreach($oBlock->getSelectors() as $oSelector) {
		//Loop over all selector parts (the comma-separated strings in a selector) and prepend the id
		$oSelector->setSelector($sMyId.' '.$oSelector->getSelector());
	}
}

将所有绝对大小缩小一半

$oParser = new Sabberworm\CSS\Parser($sText);
$oCss = $oParser->parse();
foreach($oCss->getAllValues() as $mValue) {
	if($mValue instanceof CSSSize && !$mValue->isRelative()) {
		$mValue->setSize($mValue->getSize()/2);
	}
}

删除不需要的规则

$oParser = new Sabberworm\CSS\Parser($sText);
$oCss = $oParser->parse();
foreach($oCss->getAllRuleSets() as $oRuleSet) {
	$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
	$oRuleSet->removeRule('cursor');
}

输出

要将整个 CSS 文档输出到变量中,只需使用 ->render()

$oCssParser = new Sabberworm\CSS\Parser(file_get_contents('somefile.css'));
$oCssDocument = $oCssParser->parse();
print $oCssDocument->render();

如果您想格式化输出,请传递一个 Sabberworm\CSS\OutputFormat 类型的实例

$oFormat = Sabberworm\CSS\OutputFormat::create()->indentWithSpaces(4)->setSpaceBetweenRules("\n");
print $oCssDocument->render($oFormat);

或者使用预定义的格式之一

print $oCssDocument->render(Sabberworm\CSS\OutputFormat::createPretty());
print $oCssDocument->render(Sabberworm\CSS\OutputFormat::createCompact());

要查看输出格式化的使用方法,请查看 tests/Sabberworm/CSS/OutputFormatTest.php 中的测试。

示例

示例 1(At-Rules)

输入

@charset "utf-8";

@font-face {
  font-family: "CrassRoots";
  src: url("../media/cr.ttf")
}

html, body {
    font-size: 1.6em
}

@keyframes mymove {
	from { top: 0px; }
	to { top: 200px; }
}

结构(var_dump()

class Sabberworm\CSS\CSSList\Document#4 (2) {
  protected $aContents =>
  array(4) {
    [0] =>
    class Sabberworm\CSS\Property\Charset#6 (2) {
      private $sCharset =>
      class Sabberworm\CSS\Value\CSSString#5 (2) {
        private $sString =>
        string(5) "utf-8"
        protected $iLineNo =>
        int(1)
      }
      protected $iLineNo =>
      int(1)
    }
    [1] =>
    class Sabberworm\CSS\RuleSet\AtRuleSet#7 (4) {
      private $sType =>
      string(9) "font-face"
      private $sArgs =>
      string(0) ""
      private $aRules =>
      array(2) {
        'font-family' =>
        array(1) {
          [0] =>
          class Sabberworm\CSS\Rule\Rule#8 (4) {
            private $sRule =>
            string(11) "font-family"
            private $mValue =>
            class Sabberworm\CSS\Value\CSSString#9 (2) {
              private $sString =>
              string(10) "CrassRoots"
              protected $iLineNo =>
              int(4)
            }
            private $bIsImportant =>
            bool(false)
            protected $iLineNo =>
            int(4)
          }
        }
        'src' =>
        array(1) {
          [0] =>
          class Sabberworm\CSS\Rule\Rule#10 (4) {
            private $sRule =>
            string(3) "src"
            private $mValue =>
            class Sabberworm\CSS\Value\URL#11 (2) {
              private $oURL =>
              class Sabberworm\CSS\Value\CSSString#12 (2) {
                private $sString =>
                string(15) "../media/cr.ttf"
                protected $iLineNo =>
                int(5)
              }
              protected $iLineNo =>
              int(5)
            }
            private $bIsImportant =>
            bool(false)
            protected $iLineNo =>
            int(5)
          }
        }
      }
      protected $iLineNo =>
      int(3)
    }
    [2] =>
    class Sabberworm\CSS\RuleSet\DeclarationBlock#13 (3) {
      private $aSelectors =>
      array(2) {
        [0] =>
        class Sabberworm\CSS\Property\Selector#14 (2) {
          private $sSelector =>
          string(4) "html"
          private $iSpecificity =>
          NULL
        }
        [1] =>
        class Sabberworm\CSS\Property\Selector#15 (2) {
          private $sSelector =>
          string(4) "body"
          private $iSpecificity =>
          NULL
        }
      }
      private $aRules =>
      array(1) {
        'font-size' =>
        array(1) {
          [0] =>
          class Sabberworm\CSS\Rule\Rule#16 (4) {
            private $sRule =>
            string(9) "font-size"
            private $mValue =>
            class Sabberworm\CSS\Value\Size#17 (4) {
              private $fSize =>
              double(1.6)
              private $sUnit =>
              string(2) "em"
              private $bIsColorComponent =>
              bool(false)
              protected $iLineNo =>
              int(9)
            }
            private $bIsImportant =>
            bool(false)
            protected $iLineNo =>
            int(9)
          }
        }
      }
      protected $iLineNo =>
      int(8)
    }
    [3] =>
    class Sabberworm\CSS\CSSList\KeyFrame#18 (4) {
      private $vendorKeyFrame =>
      string(9) "keyframes"
      private $animationName =>
      string(6) "mymove"
      protected $aContents =>
      array(2) {
        [0] =>
        class Sabberworm\CSS\RuleSet\DeclarationBlock#19 (3) {
          private $aSelectors =>
          array(1) {
            [0] =>
            class Sabberworm\CSS\Property\Selector#20 (2) {
              private $sSelector =>
              string(4) "from"
              private $iSpecificity =>
              NULL
            }
          }
          private $aRules =>
          array(1) {
            'top' =>
            array(1) {
              [0] =>
              class Sabberworm\CSS\Rule\Rule#21 (4) {
                private $sRule =>
                string(3) "top"
                private $mValue =>
                class Sabberworm\CSS\Value\Size#22 (4) {
                  private $fSize =>
                  double(0)
                  private $sUnit =>
                  string(2) "px"
                  private $bIsColorComponent =>
                  bool(false)
                  protected $iLineNo =>
                  int(13)
                }
                private $bIsImportant =>
                bool(false)
                protected $iLineNo =>
                int(13)
              }
            }
          }
          protected $iLineNo =>
          int(13)
        }
        [1] =>
        class Sabberworm\CSS\RuleSet\DeclarationBlock#23 (3) {
          private $aSelectors =>
          array(1) {
            [0] =>
            class Sabberworm\CSS\Property\Selector#24 (2) {
              private $sSelector =>
              string(2) "to"
              private $iSpecificity =>
              NULL
            }
          }
          private $aRules =>
          array(1) {
            'top' =>
            array(1) {
              [0] =>
              class Sabberworm\CSS\Rule\Rule#25 (4) {
                private $sRule =>
                string(3) "top"
                private $mValue =>
                class Sabberworm\CSS\Value\Size#26 (4) {
                  private $fSize =>
                  double(200)
                  private $sUnit =>
                  string(2) "px"
                  private $bIsColorComponent =>
                  bool(false)
                  protected $iLineNo =>
                  int(14)
                }
                private $bIsImportant =>
                bool(false)
                protected $iLineNo =>
                int(14)
              }
            }
          }
          protected $iLineNo =>
          int(14)
        }
      }
      protected $iLineNo =>
      int(12)
    }
  }
  protected $iLineNo =>
  int(1)
}

输出(render()

@charset "utf-8";
@font-face {font-family: "CrassRoots";src: url("../media/cr.ttf");}
html, body {font-size: 1.6em;}
@keyframes mymove {from {top: 0px;}
	to {top: 200px;}}

示例 2(值)

输入

#header {
	margin: 10px 2em 1cm 2%;
	font-family: Verdana, Helvetica, "Gill Sans", sans-serif;
	color: red !important;
}

结构(var_dump()

class Sabberworm\CSS\CSSList\Document#4 (2) {
  protected $aContents =>
  array(1) {
    [0] =>
    class Sabberworm\CSS\RuleSet\DeclarationBlock#5 (3) {
      private $aSelectors =>
      array(1) {
        [0] =>
        class Sabberworm\CSS\Property\Selector#6 (2) {
          private $sSelector =>
          string(7) "#header"
          private $iSpecificity =>
          NULL
        }
      }
      private $aRules =>
      array(3) {
        'margin' =>
        array(1) {
          [0] =>
          class Sabberworm\CSS\Rule\Rule#7 (4) {
            private $sRule =>
            string(6) "margin"
            private $mValue =>
            class Sabberworm\CSS\Value\RuleValueList#12 (3) {
              protected $aComponents =>
              array(4) {
                [0] =>
                class Sabberworm\CSS\Value\Size#8 (4) {
                  private $fSize =>
                  double(10)
                  private $sUnit =>
                  string(2) "px"
                  private $bIsColorComponent =>
                  bool(false)
                  protected $iLineNo =>
                  int(2)
                }
                [1] =>
                class Sabberworm\CSS\Value\Size#9 (4) {
                  private $fSize =>
                  double(2)
                  private $sUnit =>
                  string(2) "em"
                  private $bIsColorComponent =>
                  bool(false)
                  protected $iLineNo =>
                  int(2)
                }
                [2] =>
                class Sabberworm\CSS\Value\Size#10 (4) {
                  private $fSize =>
                  double(1)
                  private $sUnit =>
                  string(2) "cm"
                  private $bIsColorComponent =>
                  bool(false)
                  protected $iLineNo =>
                  int(2)
                }
                [3] =>
                class Sabberworm\CSS\Value\Size#11 (4) {
                  private $fSize =>
                  double(2)
                  private $sUnit =>
                  string(1) "%"
                  private $bIsColorComponent =>
                  bool(false)
                  protected $iLineNo =>
                  int(2)
                }
              }
              protected $sSeparator =>
              string(1) " "
              protected $iLineNo =>
              int(2)
            }
            private $bIsImportant =>
            bool(false)
            protected $iLineNo =>
            int(2)
          }
        }
        'font-family' =>
        array(1) {
          [0] =>
          class Sabberworm\CSS\Rule\Rule#13 (4) {
            private $sRule =>
            string(11) "font-family"
            private $mValue =>
            class Sabberworm\CSS\Value\RuleValueList#15 (3) {
              protected $aComponents =>
              array(4) {
                [0] =>
                string(7) "Verdana"
                [1] =>
                string(9) "Helvetica"
                [2] =>
                class Sabberworm\CSS\Value\CSSString#14 (2) {
                  private $sString =>
                  string(9) "Gill Sans"
                  protected $iLineNo =>
                  int(3)
                }
                [3] =>
                string(10) "sans-serif"
              }
              protected $sSeparator =>
              string(1) ","
              protected $iLineNo =>
              int(3)
            }
            private $bIsImportant =>
            bool(false)
            protected $iLineNo =>
            int(3)
          }
        }
        'color' =>
        array(1) {
          [0] =>
          class Sabberworm\CSS\Rule\Rule#16 (4) {
            private $sRule =>
            string(5) "color"
            private $mValue =>
            string(3) "red"
            private $bIsImportant =>
            bool(true)
            protected $iLineNo =>
            int(4)
          }
        }
      }
      protected $iLineNo =>
      int(1)
    }
  }
  protected $iLineNo =>
  int(1)
}

输出(render()

#header {margin: 10px 2em 1cm 2%;font-family: Verdana,Helvetica,"Gill Sans",sans-serif;color: red !important;}

贡献者/感谢

杂项

  • 遗留支持:此项目的最新预 PSR-0 版本可以通过 0.9.0 标签进行检查。
  • 运行测试:要运行此项目的所有单元测试,请运行 composer install 安装 phpunit,然后使用 ./vendor/phpunit/phpunit/phpunit

许可证

PHP-CSS-Parser 在 MIT 风格许可证的条款下免费分发。

版权所有(C)2011 Raphael Schweikert,http://sabberworm.com/

特此授予任何获得本软件及其相关文档副本(以下简称“软件”)的人士,在不受限制的情况下使用软件的权利,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售软件副本的权利,并允许软件提供者进行此类操作,前提是遵守以下条件:

上述版权声明和本许可声明应包含在软件的所有副本或主要部分中。

软件按“原样”提供,不提供任何形式的保证,无论是明示的还是暗示的,包括但不限于适销性、特定用途的适用性和非侵权性保证。在任何情况下,作者或版权所有者均不对任何索赔、损害或其他责任负责,无论此类索赔、损害或其他责任是基于合同、侵权或其他方式,以及与软件或软件的使用或其他操作有关。