2010-07-24 10 views
25

Ich versuche, so dass in JavaScript Parsing von CSS zu implementieren:Parsing CSS in JavaScript/jQuery

a { 
    color: red; 
} 

in das Objekt analysiert wird:

{ 
    'a' { 
    'color': 'red' 
    } 
} 

Zunächst einmal gibt es einen JavaScript/jQuery Bibliothek kann ich verwenden?

Meine Implementierung ist ziemlich einfach, also bin ich mir sicher, dass es auf keinen Fall narrensicher ist. Zum Beispiel arbeitet es für grundlegende CSS in Ordnung, aber für eine Eigenschaft des Typs:

background: url(data:image/png;base64, ....); 

Es schlägt fehl, weil ich split(';') bin mit property:value Paare zu trennen. Hier tritt ; im value auf, also teilt es sich auch an diesem Punkt.

Gibt es eine alternative Möglichkeit, dies zu tun? Hier

ist der Code:

parseCSS: function(css) { 
    var rules = {}; 
    css = this.removeComments(css); 
    var blocks = css.split('}'); 
    blocks.pop(); 
    var len = blocks.length; 
    for (var i = 0; i < len; i++) 
    { 
     var pair = blocks[i].split('{'); 
     rules[$.trim(pair[0])] = this.parseCSSBlock(pair[1]); 
    } 
    return rules; 
}, 

parseCSSBlock: function(css) { 
    var rule = {}; 
    var declarations = css.split(';'); 
    declarations.pop(); 
    var len = declarations.length; 
    for (var i = 0; i < len; i++) 
    { 
     var loc = declarations[i].indexOf(':'); 
     var property = $.trim(declarations[i].substring(0, loc)); 
     var value = $.trim(declarations[i].substring(loc + 1)); 

     if (property != "" && value != "") 
      rule[property] = value; 
    } 
    return rule; 
}, 

removeComments: function(css) { 
    return css.replace(/\/\*(\r|\n|.)*\*\//g,""); 
} 

Dank!

+1

Warum möchten Sie das tun? Was versuchst du zu erreichen? Vielleicht gibt es eine andere (einfachere) Art und Weise, Ihr Problem zu lösen –

+0

blau geparst zu rot ?!:) –

+0

@Pablo Ich habe versucht, über alternative Möglichkeiten nachzudenken, mit denen ich in der Lage sein könnte, die Notwendigkeit, CSS zu analysieren, aber leider muss ich die Regeln in einigen Datenstruktur speichern. Mein Projekt funktioniert damit eigentlich ganz gut, da es sich meist um grundlegende CSS-Regeln (Major Use Case) handelt. Es ist jedoch nett, narrensicher zu sein, da es einen Anwendungsfall gibt, bei dem es notwendig ist, CSS zu analysieren. – ankit

Antwort

27

Es gibt einen CSS-Parser in Javascript JSCSSP

+3

ich einen Blick habe davor, aber wollte es nicht benutzen, da es so ** schwer ist. Es macht eine Menge Sachen, die ich nicht tun muss – ankit

+9

@ankit: Was fragen Sie dann? Wenn Sie * korrekt * analysieren wollen (dh Sie können mit jedem beliebigen CSS umgehen), dann werden Sie mit einer "schweren" Bibliothek enden. Andernfalls können Sie bei Ihrer leichten Implementierung bleiben und wissen, dass es leicht zu knacken ist. – josh3736

+0

@ josh3736 Sieht so aus, als ob dein Kommentar der Push war, den ich brauchte. Ich war besorgt über Leistungsprobleme, aber es stellt sich heraus, dass es ziemlich gut funktioniert! – ankit

10

Um den idiotensichersten Parser zu schreiben, befolgen Sie die genauen Regeln für tokenization und CSS grammar, wie in der Spezifikation definiert. Beachten Sie, dass Sie die Spezifikation nicht mit der Tinte implementieren müssen. Sie können mit kleinen Teilen und CSS beginnen, denen Sie am ehesten begegnen werden, und dann von dort aus expandieren. Noch besser, überspringen Sie den gesamten Prozess und gehen Sie mit @ Matthews Lösung, es sei denn, dies ist eine Lernübung.

Es gibt verschiedene lexikalische Scanner und Parsergeneratoren für JavaScript. Die gesamte Grammatik ist auf der Website von w3 verfügbar. Warum sollten Sie das ändern, wenn Sie einfach diese und die Parser-Generatoren verwenden können, um den Parser in JavaScript zu generieren?

  1. Jison
  2. Peg.js
  3. Cruiser.Parse
  4. McLexer
  5. JS/CC

Die Produktionsregeln für CSS sind unten angegeben.

stylesheet 
    : [ CHARSET_SYM STRING ';' ]? 
    [S|CDO|CDC]* [ import [ CDO S* | CDC S* ]* ]* 
    [ [ ruleset | media | page ] [ CDO S* | CDC S* ]* ]* 
    ; 
import 
    : IMPORT_SYM S* 
    [STRING|URI] S* media_list? ';' S* 
    ; 
media 
    : MEDIA_SYM S* media_list LBRACE S* ruleset* '}' S* 
    ; 
media_list 
    : medium [ COMMA S* medium]* 
    ; 
medium 
    : IDENT S* 
    ; 
page 
    : PAGE_SYM S* pseudo_page? 
    '{' S* declaration? [ ';' S* declaration? ]* '}' S* 
    ; 
pseudo_page 
    : ':' IDENT S* 
    ; 
operator 
    : '/' S* | ',' S* 
    ; 
combinator 
    : '+' S* 
    | '>' S* 
    ; 
unary_operator 
    : '-' | '+' 
    ; 
property 
    : IDENT S* 
    ; 
ruleset 
    : selector [ ',' S* selector ]* 
    '{' S* declaration? [ ';' S* declaration? ]* '}' S* 
    ; 
selector 
    : simple_selector [ combinator selector | S+ [ combinator? selector ]? ]? 
    ; 
simple_selector 
    : element_name [ HASH | class | attrib | pseudo ]* 
    | [ HASH | class | attrib | pseudo ]+ 
    ; 
class 
    : '.' IDENT 
    ; 
element_name 
    : IDENT | '*' 
    ; 
attrib 
    : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S* 
    [ IDENT | STRING ] S* ]? ']' 
    ; 
pseudo 
    : ':' [ IDENT | FUNCTION S* [IDENT S*]? ')' ] 
    ; 
declaration 
    : property ':' S* expr prio? 
    ; 
prio 
    : IMPORTANT_SYM S* 
    ; 
expr 
    : term [ operator? term ]* 
    ; 
term 
    : unary_operator? 
    [ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* | 
     TIME S* | FREQ S* ] 
    | STRING S* | IDENT S* | URI S* | hexcolor | function 
    ; 
function 
    : FUNCTION S* expr ')' S* 
    ; 
/* 
* There is a constraint on the color that it must 
* have either 3 or 6 hex-digits (i.e., [0-9a-fA-F]) 
* after the "#"; e.g., "#000" is OK, but "#abcd" is not. 
*/ 
hexcolor 
    : HASH S* 
    ; 
+0

Diese Produktionsregeln sind für CSS3 veraltet. Ich sehe nicht, ‚~‘ zum Beispiel – huyz

+1

Sie bei Coffeescript für ein schönes gut dokumentiertes Beispiel aussehen: http://jashkenas.github.com/coffee-script/documentation/docs/grammar.html – Brandon

52

genannt geschrieben Sie bequem die Browser eigene CSSOM verwenden können, um CSS zu analysieren:

var rulesForCssText = function (styleContent) { 
    var doc = document.implementation.createHTMLDocument(""), 
     styleElement = document.createElement("style"); 

    styleElement.textContent = styleContent; 
    // the style will only be parsed once it is added to a document 
    doc.body.appendChild(styleElement); 

    return styleElement.sheet.cssRules; 
}; 

Für jede Regel zurückgegeben Sie an den Eigenschaften suchen können in rule.style. Ein Beispiel finden Sie in http://jsfiddle.net/v2JsZ/.

+3

Sie rocken! Es wirkt wie ein Zauber! :) Ich denke, es ist die beste Wahl für die Implementierung im Browser. Sie brauchen keine Bibliothek und es ist schneller als jede Bibliothek, denke ich. –

+0

Ich habe Ihre jsfiddle mit einem Beispiel aktualisiert, die nur die CSS analysiert: http://jsfiddle.net/v2JsZ/85/ –

+0

Wie kommt es, wenn meine Stile dieser Code ein Hintergrundbild haben einen leeren Pfad zurück: 'url()' ? – Moss