Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

How to parse a .css file generated by Mathematica (Export notebook to HTML)? modify values, add some values.

convert into a expression?

Are there some instances?

I've wrote a simple function to add some values to a .css file.

ImportTxt[file_, Elements_: "String"] :=  Module[{file1 = file, absoluteFileName,    fileNameTxt}, (fileNameTxt = ((FileNameDrop[           absoluteFileName = AbsoluteFileName[#]] <> "\\" <>           FileBaseName[#]) &@file) <> ".txt");   If[FileExistsQ[fileNameTxt], DeleteFile[fileNameTxt];    CopyFile[file, fileNameTxt]; Import[fileNameTxt, Elements],    CopyFile[file, fileNameTxt]; Import[fileNameTxt, Elements]]]

ExportCSS[file_, content_] :=  Module[{fileTxt = file <> ".txt", fileCss = file <> ".css"},   Export[fileTxt, content];   If[FileExistsQ[fileCss], DeleteFile[fileCss];    RenameFile[fileTxt, fileCss], RenameFile[fileTxt, fileCss]]]

cssAdd[cssFile_, name_, value_] :=  Module[{cssFileTxt},   If[FileExistsQ[cssFile] == False, Print["File-Not-Exists"];    Abort[]]; cssData = ImportTxt[cssFile, "Data"];   cssDataList =    Partition[SplitBy[cssData, StringMatchQ[#, "/*" ~~ __ ~~ "*/"] &],     2];  pos = Position[cssDataList, "." <> name <> " {"][[1]];  result = Insert[cssDataList, value, pos + {0, 0, 1}];  ExportCSS[cssFile // StringDrop[#, -4] &,    StringJoin@Map[Riffle[#, "\n"] &, result, {1, 2}]]]

For example:

cssAdd["index", "Text", "width:300px;"]

will add the value "width:300px" to the css file. The problem is the manipulation can not do repeatedly.

Now we continue to change the value width:300px; into width:500px;

The first value added is 300px; the second value is 500px; however, in .css file, the same value only take effect in the after. ie. width:300px; will override the width:500px; In my code: I use pos + {0, 0, 1} to get the position where to insert a new value, it is not good.It is hard to find the right place to insert(...Let me try Reverse a sublist...)

width:500px;

width:300px;

more completely show:

.Text{ 
width:500px;
width:300px;
padding:8px;
}

The right one should be

.Text{ 
width:300px;
width:500px;
padding:8px;
}

How to develop my function or other better functions/methods? for example, The first question is Import as "String" or "Data"?

Since PageWidth doesn't seem to take effect after exporting to HTML, I need manually map the value of PageWidth to the width in.css file.


Update one of my solution: I find the place of "}" after ".Text {"

pos1=Position[cssDataList,"."<>name<>" {"][[1]];
level=pos1[[1;;2]];
pos2=Select[Position[cssDataList,"}"][[All,-1]],#>pos1[[-1]]&]//First;
result=Insert[cssDataList,value,Append[level,pos2]];
share|improve this question
    
@cormullion hi, I think you know much about something about .css file. –  HyperGroups Dec 20 '13 at 7:27
    
500px will override 300px, yes, but isn't this what you want? –  Pickett Dec 20 '13 at 7:41
    
@Anon no, 300px override 500px, my function add a new value just after .name { –  HyperGroups Dec 20 '13 at 7:43
    
Hi - no I know very little about CSS, except that it cascades (inherits). But your question isn't clear - what are the different selectors for width. What is overriding what? And your 'parser' won't work on all CSS files (they can be very complex- even containing image data). I wonder why Mathematica doesn't parse CSS files? –  cormullion Dec 20 '13 at 8:42
    
@cormullion ah, fine, I mean the .css file generated by Mathematica Exporting notobook to HTML. –  HyperGroups Dec 20 '13 at 8:45

1 Answer 1

You've added some additional data since I started working on my solution and I now have a better understanding of your problem. You attempted to replace a value and ended up with

.Text{ 
width:500px;
width:300px;
padding:8px;
}

It's much easier to append the rule at the end of the file, so you get:

.Text{ 
width:500px;
padding:8px;
}

.Text{
width:300px;
}

This is valid CSS, where the last rule has precedence over the former. In fact, this property of CSS is very, very commonly used. For example almost every website includes a stylesheet that gets rid of browser inconsistencies. Then usually a sort of framework with handy and common rules, and then a third stylesheet with site-specific styles. Each stylesheet overrides the former. So what you ought to do is create a stylesheet that overrides the Mathematica styles you don't like and include it after you include the Mathematica stylesheet.

However, I've written a simple example of how you can work with CSS. It should work for the most common purposes. It only has one function so far, which is to add/update a property but you can easily extend it.

Let's start with some basic CSS:

css = ".navbar-inverse .navbar-brand,
  .navbar-inverse .navbar-nav > li > a {
    text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
  }

  .navbar-static-top,
  .navbar-fixed-top,
  .navbar-fixed-bottom {
    border-radius: 0;
  }

  .alert {
    text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);
    -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 \
1px 2px rgba(0, 0, 0, 0.05);
            box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 \
1px 2px rgba(0, 0, 0, 0.05);
  }

  .alert-success {
    background-image: -webkit-linear-gradient(top, #dff0d8 0%, \
#c8e5bc 100%);
    background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc \
100%);
    background-repeat: repeat-x;
    border-color: #b2dba1;
    filter: \
progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', \
endColorstr='#ffc8e5bc', GradientType=0);
  }";

Here's the parser, I hope it's clear what it does from the comments. The regular expressions are very simple, one can think of them as string patterns where .*? is _.

{selectors, properties} = 
  Transpose@
   StringCases[StringReplace[css, "\n" -> ""](* The . 
    selector does not match newlines *),
    RegularExpression["(.*?){(.*?)}"] -> {"$1", 
          "$2"} (* $1 is the content of the first parenthesis, $2 that of \
the second *)
    ];
selectors = 
  StringTrim /@ 
   StringSplit[selectors, ","]; (* Selectors are divided by comma *)

properties = 
  StringTrim /@ 
     StringCases[#, 
      RegularExpression["(.*?):(.*?);"] -> {"$1", "$2"}] & /@ 
   properties; (* Each property is of the form name: value; *)

rules = Transpose[{selectors, properties}];

Now execute rules // TableForm and inspect the values. To change a value I created this utility function:

propertyUpdate[rules_, selector_, name_, value_] := If[
  MatchQ[rules, {___, {{___, 
      selector, ___}, {___, {name, ___}, ___}}, ___}](* 
  The property already has a value *),
  rules /. {x___, {s : {___, selector, ___}, {a : ___, {name, ___}, 
       b : ___}}, y___} :> {x, {s, {a, {name, value}, b}}, y},
  Append[rules, {selector, {{name, value}}}]
  ]

To try it, execute this and compare with the original value:

propertyUpdate[rules, ".alert", "box-shadow", "newValue"] // TableForm
share|improve this answer
    
ha, thanks, I need time to digest your answer. I see one important thing is we can just add a total .Text {width:300px;} in the end of the file, that broaden the functions we could write. I've added a solution along my function, find the place of "}". –  HyperGroups Dec 20 '13 at 9:17

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.