see whatever…

jump to menu

March 8, 2009

property filter with cssutils

Filed under: cssutils — see @ 6:22 pm

cssutils 0.9.6a2 has just been released and the main new feature probably is custom property profiles. You might want to filter any given stylesheet on certain properties. This might be predefined ones (like CSS 2 properties like e.g. “color”)  or predefined ones but with a limited set of possible values or even custom properties with custom values.

Example

Following a simple example how to define a custom profile and filter any given sheet (at least style declaration properties, filtering of certain @rules is not shown):

import cssutils
# remove ALL predefined property profiles
cssutils.profile.removeProfile(all=True)

# add your custom profile, {num} is defined in Profile and always available
macros = {'myvalue': 'a|b|c'}
props = {'abc': '{myvalue}|{num}', 'color': 'red|blue'}
cssutils.profile.addProfile('my-profile', props, macros)

# keep only valid properties (valid in given profile)
cssutils.ser.prefs.validOnly = True

print cssutils.parseString('''a {
    color: green;
    color: red;
    abc: 1;
    abc: b;
    abc: 1 a
}''').cssText

results in (some messages may be doubled – not shown here – because messages are output on parsing AND during serializing):

ERROR   Property: Invalid value for "my-profile" property: green [2:9: color]
ERROR   Property: Invalid value for "my-profile" property: 1 a [6:9: abc]
a {
    color: red;
    abc: 1;
    abc: b;
    }

How to

To define your custom property profile you just need to define the properties with the possible values in a standard dictionary. Each key is a property name, each value a regular expression defining valid values. Actually the value is not (yet) a regular regular expression but may contain macros which may be used to simplify the definitions. Each macro is defined with enclosing {} and must start with [a-z]. You may define your own macros (“myvalue” in the above example) or you may use predefined macros. The basic ones are defined in cssutils.profile directly. To get a list use:

import cssutils, pprint
print "TOKEN_MACROS"
pprint.pprint(cssutils.profile._TOKEN_MACROS)
print "MACROS"
pprint.pprint(cssutils.profile._MACROS)

resulting currently in:

TOKEN_MACROS
{'escape': '{unicode}|\\\\[ -~\\200-\\777]',
 'ident': '[-]?{nmstart}{nmchar}*',
 'int': '[-]?\\d+',
 'name': '{nmchar}+',
 'nl': '\\n|\\r\\n|\\r|\\f',
 'nmchar': '[\\w-]|{nonascii}|{escape}',
 'nmstart': '[_a-z]|{nonascii}|{escape}',
 'nonascii': '[^\\0-\\177]',
 'num': '[-]?\\d+|[-]?\\d*\\.\\d+',
 'number': '{num}',
 'string': '{string1}|{string2}',
 'string1': '"(\\\\\\"|[^\\"])*"',
 'string2': "'(\\\\\\'|[^\\'])*'",
 'unicode': '\\\\[0-9a-f]{1,6}(\\r\\n|[ \\n\\r\\t\\f])?',
 'uri': 'url\\({w}({string}|(\\\\\\)|[^\\)])+){w}\\)',
 'w': '\\s*'}
MACROS
{'angle': '0|{num}(deg|grad|rad)',
 'color': '{namedcolor}|{hexcolor}|{rgbcolor}|{uicolor}',
 'frequency': '0|{num}k?Hz',
 'hexcolor': '#[0-9a-f]{3}|#[0-9a-f]{6}',
 'integer': '{int}',
 'length': '0|{num}(em|ex|px|in|cm|mm|pt|pc)',
 'namedcolor': '(transparent|orange|maroon|red|orange|yellow|olive|purple|fuchsi
a|white|lime|green|navy|blue|aqua|teal|black|silver|gray)',
 'percentage': '{num}%',
 'rgbcolor': 'rgb\\({w}{int}{w},{w}{int}{w},{w}{int}{w}\\)|rgb\\({w}{num}%{w},{w
}{num}%{w},{w}{num}%{w}\\)',
 'time': '0|{num}m?s',
 'uicolor': '(ActiveBorder|ActiveCaption|AppWorkspace|Background|ButtonFace|Butt
onHighlight|ButtonShadow|ButtonText|CaptionText|GrayText|Highlight|HighlightText
|InactiveBorder|InactiveCaption|InactiveCaptionText|InfoBackground|InfoText|Menu
|MenuText|Scrollbar|ThreeDDarkShadow|ThreeDFace|ThreeDHighlight|ThreeDLightShado
w|ThreeDShadow|Window|WindowFrame|WindowText)'}

You may also use any macro defined in the predefined profiles. As these may use other macros all have to be added (in the following example the “‘identifier” macro):

from cssutils.profiles import macros as predef
from cssutils import profile
macros = {'my-font': predef[profile.CSS_LEVEL_2]['family-name'],
          'identifier': predef[profile.CSS_LEVEL_2]['identifier']}
props = {'f': '{my-font}'}
cssutils.profile.addProfile('my-font-profile', props, macros)
print cssutils.parseString('''a {
    f: 1; /* 1 is invalid! */
    f: Arial;
}''').cssText

resulting in:

ERROR   Property: Invalid value for "my-profile2" property: 1 [2:9: f]
a {
    /* 1 is invalid! */
    f: Arial
    }

I hope this does not feel to complicate… If you have any suggestions or questions please try the cssutils Google Group.

Powered by WordPress