Parsowanie CSS w JavaScript / jQuery

Próbuję zaimplementować parsowanie CSS w JavaScript tak, aby:

a {
  color: red;
}

Jest parsowane do obiektu:

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

Po pierwsze, czy istnieje biblioteka JavaScript / jQuery , której mogę użyć?

Moja implementacja jest dość podstawowa, więc jestem pewien, że nie jest w żaden sposób niezawodna. Na przykład, działa dobrze dla podstawowego CSS, ale dla właściwości typu:

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

Nie powiodło się, ponieważ używam split(';') do oddzielania property:value par. Tutaj ; występuje w value, więc dzieli się w tym momencie też.

Czy jest inny sposób, aby to zrobić?

Oto kod:

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,"");
}
Dzięki!
Author: Gumbo, 2010-07-24

4 answers

Istnieje parser CSS napisany w Javascript o nazwie JSCSSP

 27
Author: Matthew Manela,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-24 19:33:19

Możesz łatwo użyć własnego CSSOM przeglądarki do parsowania CSS:

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;
};

Dla każdej zwróconej reguły możesz spojrzeć na właściwości w rule.style. Zobacz http://jsfiddle.net/v2JsZ / na przykład.

 57
Author: cburgmer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-14 00:12:33

Aby napisać najbardziej niezawodny parser, postępuj zgodnie z dokładnymi zasadami tokenizacji i gramatyki CSS zdefiniowanymi w specyfikacji. Zauważ, że nie musisz implementować specyfikacji za pomocą atramentu. Możesz zacząć od małych części i CSS, które najprawdopodobniej napotkasz, a następnie rozwinąć stamtąd. Nawet lepiej, pomiń cały proces całkowicie i przejdź do rozwiązania @ Matthew, chyba że jest to ćwiczenie uczenia się.

Istnieją różne Skanery leksykalne i generatory parserów dostępne dla JavaScript. Cała gramatyka jest dostępna na stronie internetowej w3. Po co robić przeróbkę, skoro można po prostu użyć tego I GENERATORÓW parserów do wygenerowania parsera w JavaScript.

  1. Jison
  2. Peg.js
  3. Krążownik.Parse
  4. McLexer
  5. JS / CC

Reguły produkcji dla CSS są podane poniżej.

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*
  ;
 11
Author: Anurag,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-24 19:41:09

Prosty przykład, nie testowany, ale powinien działać, używam podobnego w moim projekcie.

var div = jQuery('<div/>');
div[0].style = 'position:absolute;left:5px;top:10px;'; //Css to parse

div.css('left'); // => '5px'
div.css('top'); // => '10px'
div[0].style; // => Object containing all css
 0
Author: Olexiy Zamkoviy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-21 09:12:51