最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - how to convert css string into array - Stack Overflow

programmeradmin5浏览0评论

Well here is what I'm trying to do. I want to convert a array which contains CSS rules like so:

[

".divd { bottom: 0px; height: 500px; }"

, 

".divk { font-size: 14px; }"

]

I want to turn this into:

cssarray['divd'] =  {
        bottom: "0px",
        height: "500px",
    };

Here is what i've done so far:

    var splitSelector= css.split("{");
    var splitProperty = split[1].split(";");
    var v =[];
    for(i in splitProperty ){
        v = $.extend(v,splitProperty[i].split(":"));
    }

I have tried to get this work with lot's of split statements but im out of luck.

Well here is what I'm trying to do. I want to convert a array which contains CSS rules like so:

[

".divd { bottom: 0px; height: 500px; }"

, 

".divk { font-size: 14px; }"

]

I want to turn this into:

cssarray['divd'] =  {
        bottom: "0px",
        height: "500px",
    };

Here is what i've done so far:

    var splitSelector= css.split("{");
    var splitProperty = split[1].split(";");
    var v =[];
    for(i in splitProperty ){
        v = $.extend(v,splitProperty[i].split(":"));
    }

I have tried to get this work with lot's of split statements but im out of luck.

Share Improve this question edited Oct 13, 2012 at 12:04 Toon Krijthe 53.5k38 gold badges149 silver badges203 bronze badges asked Oct 13, 2012 at 11:57 Hussein NazzalHussein Nazzal 2,55720 silver badges35 bronze badges 1
  • 2 Your code is only handling rules for css classes... How would your cssarray look for a div.divd selector? Would it be cssarray['div.divd']? It now has 'divd' as a key which means it ignores the preceding dot in the selector. – ewino Commented Oct 13, 2012 at 12:04
Add a ment  | 

6 Answers 6

Reset to default 4

See this fiddle: http://jsfiddle/YrQ7B/3/

    var arr = [".divd { bottom: 0px; height: 500px; }", 
"#divk { font-size: 14px; }"];

var output = {};
for(var k in arr)
{
    var value = arr[k], key;
    // Get key
    value.replace(/(\.|#)([a-z\s]+){/gi, function($1, $2, $3){
          key = $3;
    });
    // Make object
    output[key] = {};

    // Replace First part
    value = value.replace(/\.([a-z\s]+) {/gi, "");
    value = value.replace("}", "");

    value.replace(/([a-z\-]+)([^:]+)?:([^0-9a-z]+)?([^;]+)/g, function($1, $2, $3, $4, $5){             
        output[key][$2] = $5;
    });
}

console.log(output);
​
​

The log:

Object
    divd: Object
        bottom: "0px"
        height: "500px"
    divk: Object
        font-size: "14px"

Unfortunately parsing CSS tokens is not exactly as easy as splitting a string, in fact, you ideally will need a parser, and I would suggest the use of an existing CSS parser for your task:

  • JQuery CSS Parser
  • JSCSSP

a no-RegExp method

var cssObj = {},
    arr = [".divd { bottom: 0px; height: 500px; }", ".divk { font-size: 14px; }"],
    arr_i = arr.length,
    i, j, k, str,
    sel, vals, val;
while(arr_i-- > 0){       // loop over array
    str = arr[arr_i];
    i = str.indexOf('{');
    sel = str.slice(0,i); // get Selector
    vals = str.slice(i+1,str.lastIndexOf('}'));           // get values
    val = vals.slice(0,vals.lastIndexOf(';')).split(';'); // and put in array
    cssObj[sel] = {};
    k = val.length;
    while(k-- > 0){
        j = val[k].indexOf(':');                      // get name-value pair
        cssObj[sel][val[k].slice(0,j).trim()] = val[k].slice(j+1).trim();
    }
}
console.log(cssObj); // see output

for use as function, pass arr and change console.log to return. The .slice(0,vals.lastIndexOf(';')) assumes you end the last entry before the } with a semicolon. If you don't want to assume this, take it out and check last array item isn't blank/whitespace.

jsperf vs RegExp method

I've used this in the past, but only when I knew exactly what I would be sending into the regexp - mainly because I'm sure there will be syntax out there that could break it (especially with the likes of mixins, css animations, css variables, and media queries). It's for these reasons why you should probably follow Mario's answer.

However, it has worked on the majority of my own css files that I've thrown at it and may help others out there... It isn't tailored to work with an array structure like you are using though, but that could be easily changed. Obivously you could optimise things by getting rid of RegExp and just using indexOf as shhac has done, but I find the expressiveness of RegExp far easier to work with and far easier to extend if and when you need to.

A few notes

  1. It assumes there are no ments in the CSS - you could always add a replace to strip ments.
  2. It relies on JSON.parse method being available - you could always include a non JSON fallback.

The code with ments:

window.onload = function(){
  /// this is designed to find a <style> element in the page with id="css"
  var entireStylesheetString = document.getElementById('css').innerHTML;
  var css = String('{'+entireStylesheetString+'}')
    /// convert double quotes to single to avoid having to escape
    .replace(/"/gi,"'")
    /// replace all whitespace sequences with single space
    .replace(/\s+/g,' ')
    /// sort the first open brace so things are neat
    .replace(/^{/,'{\n')
    /// sort the newlines so each declaration is on own line
    .replace(/\}/g,'}\n')
    /// find the selectors and wrap them with quotes for JSON keys
    .replace(/\n\s*([^\{]+)\s+?\{/g,'\n"$1":{')
    /// find an attribute and wrap again with JSON key quotes
    .replace(/([\{;])\s*([^:"\s]+)\s*:/g,'$1"$2":')
    /// find values and wrap with JSON value quotes
    .replace(/":\s*([^\}\{;]+)\s*(;|(\}))/g,'":"$1",$3')
    /// add mas after each JSON object
    .replace(/\}/g,'},')
    /// make sure we don't have too many mas
    .replace(/,\s*\}/g,'}');
  /// remove the final end ma
  css = css.substring(0,css.length-2);
  try{
    /// parse using JSON
    console.log(JSON.parse(css));
  }catch(ee){
    console.log(ee);
  }
};

The code by it's lonesome:

window.onload = function(){
  var entireStylesheetString = document.getElementById('css').innerHTML;
  var css = String('{'+entireStylesheetString+'}')
    .replace(/"/gi,"'")
    .replace(/\s+/g,' ')
    .replace(/^{/,'{\n')
    .replace(/\}/g,'}\n')
    .replace(/\n\s*([^\{]+)\s+?\{/g,'\n"$1":{')
    .replace(/([\{;])\s*([^:"\s]+)\s*:/g,'$1"$2":')
    .replace(/":\s*([^\}\{;]+)\s*(;|(\}))/g,'":"$1",$3')
    .replace(/\}/g,'},')
    .replace(/,\s*\}/g,'}');
  css = css.substring(0,css.length-2);
  try{console.log(JSON.parse(css));}catch(ee){console.log(ee);}
};

I am not a proponent of eval, but if you convert

. to ["

first space to "]=

: to :"

; to ",

Then an eval will set the whole thing

You might be able simply append a style tag;

var data=[".divd { bottom: 0px; height: 500px; }", 
".divk { font-size: 14px; }"
]

var $style=$('<style>');

$.each( data, function(i, item){
  $style.append( item + ';');
})

$('head').append($style)
发布评论

评论列表(0)

  1. 暂无评论