Ejemplo n.º 1
0
 /**
  * CSS の構文を解析します。
  *
  * @param string $data CSS データ。
  * @author Naomichi Yamakita <*****@*****.**>
  */
 private function parseCSS($data)
 {
     $encoding = mb_detect_encoding($data, 'UTF-8, eucjp-win, sjis-win, iso-2022-jp');
     if ($encoding !== 'UTF-8') {
         $data = mb_convert_encoding($data, 'UTF-8', $encoding);
     }
     $this->_htmlCSS->parseString($data);
 }
Ejemplo n.º 2
0
 public function apply($document, $base_dir = '')
 {
     if (!$base_dir) {
         $base_dir = $this->base_dir;
     }
     // XHTMLをパース
     $dom = new DOMDocument();
     $dom->loadHTML($document);
     $dom_xpath = new DOMXPath($dom);
     // 外部参照のCSSファイルを抽出する
     $nodes = $dom_xpath->query('//link[@rel="stylesheet" or @type="text/css"] | //style[@type="text/css"]');
     $add_style = array();
     $psudo_classes = array('a:hover', 'a:link', 'a:focus', 'a:visited');
     foreach ($nodes as $key => $node) {
         // CSSをパース
         $html_css = new HTML_CSS();
         if ($node->tagName == 'link' && ($href = $node->attributes->getNamedItem('href'))) {
             // linkタグの場合
             if (!file_exists($base_dir . $href->nodeValue)) {
                 throw new UnexpectedValueException('ERROR: ' . $base_dir . $href->nodeValue . ' file does not exist');
             }
             #TODO: @importのサポート
             $css_string = file_get_contents($base_dir . $href->nodeValue);
         } else {
             if ($node->tagName == 'style') {
                 // styleタグの場合
                 $css_string = $node->nodeValue;
             }
         }
         $css_error = $html_css->parseString($css_string);
         if ($css_error) {
             throw new RuntimeException('ERROR: css parse error');
         }
         // a:hover, a:link, a:focus a:visited を退避
         foreach ($psudo_classes as $psude_class) {
             $block = $html_css->toInline($psude_class);
             if (!$block) {
                 continue;
             }
             $add_style[] = $psude_class . '{' . $block . '}';
         }
         // CSSをインライン化
         $css = $html_css->toArray();
         foreach ($css as $selector => $style) {
             #TODO: 疑似要素のサポート
             // 疑似要素と@ルールはスルー(selectorToXPath的にバグでやすい)
             if (strpos($selector, '@') !== false) {
                 continue;
             }
             if (strpos($selector, ':') !== false) {
                 continue;
             }
             $xpath = selectorToXPath::toXPath($selector);
             $elements = $dom_xpath->query($xpath);
             if ($elements->length == 0) {
                 continue;
             }
             // inlineにするCSS文を構成(toInline($selector)だとh2, h3 などでうまくいかないバグ?があったため)
             $inline_style = '';
             foreach ($style as $k => $v) {
                 $inline_style .= $k . ':' . $v . ';';
             }
             foreach ($elements as $element) {
                 if ($attr_style = $element->attributes->getNamedItem('style')) {
                     // style要素が存在する場合は追記
                     if (substr($attr_style->nodeValue, -1) != ';') {
                         $inline_style = ';' . $inline_style;
                     }
                     $attr_style->nodeValue .= $inline_style;
                 } else {
                     // style要素が存在しない場合は追加
                     $element->setAttribute('style', $inline_style);
                 }
             }
         }
         // 読み込み終わったノードを削除
         $parent = $node->parentNode;
         $parent->removeChild($node);
     }
     // 疑似クラスを<style>タグとして追加
     if (!empty($add_style)) {
         $new_style = implode(PHP_EOL, $add_style);
         $new_style = implode(PHP_EOL, array('<![CDATA[', $new_style, ']]>'));
         $head = $dom_xpath->query('//head');
         $new_style_node = new DOMElement('style', $new_style);
         $head->item(0)->appendChild($new_style_node)->setAttribute('type', 'text/css');
     }
     return $dom->saveHTML();
 }