1 post tagged “css”
Friend of mine asked for something to merge two stylesheets together. I've been dinking with Python here and there when I have the time, and this was the result. It could definitely be improved, namely to work with X number of stylesheets, but it will do for now.
I like Python. Better than Ruby, actually, mainly because Ruby is too Perl-ish for my tastes. Nothing against either Ruby or Perl from a technical standpoint, just a matter of personal preference.
[--Begin--]
from __future__ import with_statement
import re
class Stylesheet:
def __init__(self):
self.cssClasses = []
def addClass(self, cssClass):
self.cssClasses.append(cssClass)
def updateClass(self, changedCssClass):
for cssClass in self.cssClasses:
if cssClass.className == changedCssClass.className:
cssClass = changedCssClass
def getClass(self, className):
for cssClass in self.cssClasses:
if cssClass.className == className:
return cssClass
def getClassNames(self):
names = []
[names.append(cssClass.className) for cssClass in self.cssClasses]
return names
def __len__(self):
return len(self.cssClasses)
def __str__(self):
cssStr = str()
self.cssClasses.sort()
for cssClass in self.cssClasses:
cssStr = cssStr + str(cssClass)
return cssStr
@staticmethod
def parseStylesheet(filename):
"""Given a physical stylesheet filename, parses it and returns a Stylesheet object."""
cssRegex = re.compile(r'\s*(.*?)\s?\{(.*?)\}', re.DOTALL)
cssDefRegex = re.compile(r'\s*?(\w.*?):\s*(.*)')
css = Stylesheet()
with open(filename) as cssFile:
classes = re.findall(cssRegex, cssFile.read())
for cssClassTuple in classes:
classStyles = []
if cssClassTuple[0].find(',') != -1:
commaClasses = cssClassTuple[0].split(',')
else:
commaClasses = [cssClassTuple[0]]
for cssClassName in commaClasses:
cssClass = CssClass(cssClassName, [])
# Now get the CssStyle objects
tmpList = cssClassTuple[1].split(';')
for cssDef in tmpList:
cssSplit = cssDefRegex.split(cssDef)
if len(cssSplit) >= 3:
style = CssStyle(cssSplit[1], cssSplit[2])
cssClass.addStyle(style)
css.addClass(cssClass)
return css
@staticmethod
def merge(css1, css2):
"""Takes two Stylesheet objects and merges them, returning the merged results"""
classes1Names = set(css1.getClassNames())
classes2Names = set(css2.getClassNames())
# This gets the classes that are in the 2nd sheet but not in the first
nameIntersection = classes1Names.intersection(classes2Names)
for name in nameIntersection:
cssClass = css1.getClass(name)
cssClass.addStyles(css2.getClass(name).cssStyles)
css1.updateClass(cssClass)
# Now get the ones that are in the 2nd one but not the first, and add them to the first
nameDiff = classes2Names.difference(classes1Names)
for name in nameDiff:
css1.addClass(css2.getClass(name))
return css1
class CssClass:
def __init__(self, className, cssStyles):
"""className: String representing the CSS class name"""
"""cssStyles: List of CssStyle objects"""
self.className = className.strip()
self.cssStyles = cssStyles
def addStyle(self, cssStyle):
"""Takes a CssStyle object and adds it to this class. If the style definition already exists it is ignored."""
if self.cssStyles.count(cssStyle) == 0:
self.cssStyles.append(cssStyle)
def addStyles(self, cssStyles):
"""Takes a List of CssStyle objects and adds them to this class. If the style definition already exists it is ignored."""
[self.addStyle(cssStyle) for cssStyle in cssStyles]
def __str__(self):
if len(self.cssStyles) > 0:
classStr = "\n" + self.className + ": {\n"
self.cssStyles.sort()
for cssStyle in self.cssStyles:
classStr = classStr + str(cssStyle)
classStr = classStr + "}\n"
return classStr
else:
return
def __cmp__(self, other):
return cmp(self.className, other.className)
def __hash__(self):
val = hash(self.className)
for cssStyle in self.cssStyles:
val+=hash(cssStyle)
return val
class CssStyle:
def __init__(self, prop, val):
self.property = prop.strip()
self.val = val.strip()
def __str__(self):
return "\t" + self.property + ": " + self.val + ";\n"
def __eq__(self, other):
return (self.property == other.property) & (self.val == other.val)
def __cmp__(self, other):
return cmp(self.property, other.property)
def __hash__(self):
return self.property.__hash__() + self.val.__hash__()
# Main logic begins here
css1 = Stylesheet.parseStylesheet('./ms1.css')
css2 = Stylesheet.parseStylesheet('./ms2.css')
merged = Stylesheet.merge(css1, css2)
with open('./merged.css', 'w') as newCssFile:
newCssFile.write(str(merged))
print "Wrote %d classes to merged.css" % len(merged)