2009-07-31 11 views
6

Quería romper un archivo css en una matriz con PHP.Rompe un archivo CSS en una matriz con PHP

Ex:

#selector{ display:block; width:100px; } 
#selector a{ float:left; text-decoration:none; } 

en una matriz de php ...

array(2) { 
    ["#selector"] => array(2) { 
    [0] => array(1) { 
     ["display"] => string(5) "block" 
    } 
    [1] => array(1) { 
     ["width"] => string(5) "100px" 
    } 
    } 
    ["#selector a"] => array(2) { 
    [0] => array(1) { 
     ["float"] => string(4) "left" 
    } 
    [1] => array(1) { 
     ["text-decoration"] => string(4) "none" 
    } 
    } 
} 

¿Alguna idea?

Oh: Editar: No me preocupan los archivos CSS mal formados en esta instancia. No debe ser a prueba de balas mientras no sea codicioso

+0

Oops Escribí algo que lo hizo al revés. –

Respuesta

11

Esto debe hacerlo:

<?php 

$css = <<<CSS 
#selector { display:block; width:100px; } 
#selector a { float:left; text-decoration:none } 
CSS; 

// 
function BreakCSS($css) 
{ 

    $results = array(); 

    preg_match_all('/(.+?)\s?\{\s?(.+?)\s?\}/', $css, $matches); 
    foreach($matches[0] AS $i=>$original) 
     foreach(explode(';', $matches[2][$i]) AS $attr) 
      if (strlen(trim($attr)) > 0) // for missing semicolon on last element, which is legal 
      { 
       list($name, $value) = explode(':', $attr); 
       $results[$matches[1][$i]][trim($name)] = trim($value); 
      } 
    return $results; 
} 
var_dump(BreakCSS($css)); 

Explicación rápida: La expresión regular es simple y aburrido. Simplemente combina todo "cualquier cosa, espacio posible, abrazadera, espacio posible, cualquier cosa, cierre el soporte". A partir de ahí, la primera coincidencia es el selector, la segunda coincidencia es la lista de atributos. Dividir eso por punto y coma, y ​​te quedan pares de clave/valor. Algunos trim() están ahí para deshacerse del espacio en blanco, y eso es todo.

Supongo que su próxima mejor opción sería explotar el selector por una coma para que pueda consolidar los atributos que se aplican a la misma cosa, etc., pero lo guardaré para usted. :)

Editar: Como se mencionó anteriormente, un analizador gramatical real sería más práctico ... pero si se está asumiendo un CSS bien formado, no hay ninguna razón por la que deba hacer nada más allá de "algo { cualquier cosa }". Depende de lo que quieras hacer con eso, realmente.

+0

..'sexplode() '¿eh? Hice una doble inspección y revisé el manual: P – Dan

+0

He traducido esto a Python durante un proceso de migración en uno de mis proyectos, si está interesado, [verifíquelo] (https: //gist.github .com/pooh110andco/5177066). – Ale

+1

Error en las reglas comentadas :-( – sumid

2

Si yo fuera usted, construiría (o encontraría) una gramática real para CSS, y analizaría de esa manera. Tratar de escribir un analizador para cualquier lenguaje de expresión no trivial (y CSS claramente no es trivial, con todos los selectores elegantes) me ha metido en problemas más que suficientes veces.

Ejemplo: http://www.phpclasses.org/package/1289-PHP-CSS-parser-class.html

7

Si necesita lo mismo para las reglas CSS con selectores múltiples y con líneas de rotura:

<?php      
$css = " 
#selector 
{ display:block; 
width:100px; 
} 
#selector a:hover div.asd, #asd h1.asd { 
float:left; 
text-decoration:none; 
} 
"; 
preg_match_all('/(?ims)([a-z0-9\s\,\.\:#_\[email protected]]+)\{([^\}]*)\}/', $css, $arr); 

$result = array(); 
foreach ($arr[0] as $i => $x) 
{ 
    $selector = trim($arr[1][$i]); 
    $rules = explode(';', trim($arr[2][$i])); 
    $result[$selector] = array(); 
    foreach ($rules as $strRule) 
    { 
     if (!empty($strRule)) 
     { 
      $rule = explode(":", $strRule); 
      $result[$selector][][trim($rule[0])] = trim($rule[1]); 
     } 
    } 
} 

var_dump($result); 
?> 

de salida:

array(2) { 
    ["#selector"]=> 
    array(2) { 
    [0]=> 
    array(1) { 
     ["display"]=> 
     string(5) "block" 
    } 
    [1]=> 
    array(1) { 
     ["width"]=> 
     string(5) "100px" 
    } 
    } 
    ["#selector a:hover div.asd, #asd h1.asd"]=> 
    array(2) { 
    [0]=> 
    array(1) { 
     ["float"]=> 
     string(4) "left" 
    } 
    [1]=> 
    array(1) { 
     ["text-decoration"]=> 
     string(4) "none" 
    } 
    } 
} 

Actualización: Se ha añadido soporte para múltiples selectores como: .box, .element , div {...}

+0

No funciona correctamente si el selector es múltiple: .box, .element, div {...} – setty

+0

Lo actualizó. Gracias. – inakiabt

+1

Bueno, pero no funciona con 'background-image: url ("data: image/png; base64, ........' tipo de valores ... –

Cuestiones relacionadas