2010-07-24 30 views
25

Tôi đang cố gắng để thực hiện phân tích cú pháp của CSS bằng JavaScript để:Parsing CSS bằng JavaScript/jQuery

a { 
    color: red; 
} 

được phân tách thành các đối tượng:

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

Trước hết, là có một Javascript/jQuery thư viện Tôi có thể sử dụng?

Việc triển khai của tôi khá cơ bản, vì vậy tôi chắc chắn nó không phải là bằng chứng lừa đảo bằng bất kỳ phương tiện nào. Ví dụ, nó hoạt động tốt cho CSS cơ bản, nhưng đối với một tài sản của các loại:

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

Nó thất bại vì tôi đang sử dụng để tách split(';')property:value cặp. Ở đây, ; xảy ra trong các value, do đó, nó chia tách tại điểm đó quá.

Có cách nào khác để thực hiện việc này không?

Đây là mã:

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,""); 
} 

Cảm ơn!

+1

Tại sao bạn muốn làm điều đó? bạn đang cố gắng đạt được điều gì. Có thể có cách khác (đơn giản hơn) để giải quyết vấn đề của bạn –

+0

màu xanh được phân tích thành màu đỏ ?!:) –

+0

@Pablo Tôi đã cố gắng hết sức để nghĩ ra các cách thay thế mà tôi có thể tránh được sự cần thiết phải phân tích cú pháp CSS, nhưng thật không may, tôi cần phải lưu trữ các quy tắc trong một số cấu trúc dữ liệu. Dự án của tôi thực sự hoạt động khá tốt với điều này, vì nó chủ yếu liên quan đến các quy tắc CSS cơ bản (trường hợp sử dụng chính). Tuy nhiên, nó sẽ được tốt đẹp để được fool-proof vì có một trường hợp sử dụng, nơi nó có thể cần phải phân tích cú pháp bất kỳ CSS. – ankit

Trả lời

27

Có một phân tích cú pháp CSS viết bằng javascript gọi JSCSSP

+3

Tôi đã xem xét lúc trước, nhưng không muốn sử dụng nó vì nó quá nặng **. Nó có rất nhiều thứ tôi không cần phải làm – ankit

+9

@ankit: Vậy bạn đang yêu cầu điều gì? Nếu bạn muốn phân tích cú pháp * một cách chính xác * (nghĩa là bạn có thể xử lý bất kỳ CSS tùy ý nào), thì bạn sẽ kết thúc với một thư viện "nặng". Nếu không, bạn có thể gắn bó với việc thực hiện nhẹ của bạn biết rằng nó dễ dàng để phá vỡ. – josh3736

+0

@ josh3736 Có vẻ như bình luận của bạn là sự thúc đẩy mà tôi yêu cầu. Tôi đã lo lắng về vấn đề hiệu suất, nhưng hóa ra nó hoạt động khá tốt! – ankit

10

Để viết trình phân tích cú pháp chống lừa đảo nhất, hãy thực hiện theo các quy tắc chính xác cho tokenization và CSS grammar như được xác định trong thông số kỹ thuật. Lưu ý rằng bạn không phải triển khai thông số bằng mực. Bạn có thể bắt đầu với các phần nhỏ và CSS mà bạn rất có thể sẽ gặp phải, và sau đó mở rộng từ đó. Thậm chí tốt hơn, bỏ qua toàn bộ quá trình và đi với giải pháp @ Matthew trừ khi đây là một bài tập học tập.

Có nhiều trình quét từ vựng và trình tạo phân tích cú pháp khác nhau có sẵn cho JavaScript. Toàn bộ ngữ pháp có sẵn trên trang web của w3. Tại sao lại làm việc khi bạn có thể sử dụng đơn giản và trình tạo phân tích cú pháp để tạo trình phân tích cú pháp trong JavaScript.

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

Các quy tắc sản xuất cho CSS được đưa ra dưới đây.

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

Các quy tắc sản xuất này đã lỗi thời đối với CSS3. Tôi không thấy '~' ví dụ – huyz

+1

Bạn có thể xem CoffeeScript để có một ví dụ được tài liệu tốt đẹp: http://jashkenas.github.com/coffee-script/documentation/docs/grammar.html – Brandon

52

Bạn có thể dễ dàng sử dụng CSSOM riêng của Trình duyệt để phân tích 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; 
}; 

Đối với mỗi quy tắc trở lại, bạn có thể nhìn vào các thuộc tính trong rule.style. Xem http://jsfiddle.net/v2JsZ/ để biết ví dụ.

+3

Bạn đá! Nó hoạt động như một say mê! :) Tôi cho rằng đó là lựa chọn tốt nhất để thực hiện trong trình duyệt. Bạn không cần bất kỳ thư viện nào và nó nhanh hơn bất kỳ thư viện nào, tôi nghĩ vậy. –

+0

Tôi đã cập nhật jsfiddle của bạn với một ví dụ chỉ phân tích cú pháp css: http://jsfiddle.net/v2JsZ/85/ –

+0

Làm cách nào nếu kiểu của tôi có hình nền, mã này trả về một đường dẫn trống: 'url()' ? – Moss