Given a list of declarations, return a list of output.Rule objects.

def get_text_rule_groups(declarations):
    """ Given a list of declarations, return a list of output.Rule objects.
    """
    property_map = {'text-anchor-dx': 'anchor_dx', # does nothing
                    'text-anchor-dy': 'anchor_dy', # does nothing
                    'text-align': 'horizontal_alignment',
                    'text-allow-overlap': 'allow_overlap',
                    'text-avoid-edges': 'avoid_edges',
                    'text-character-spacing': 'character_spacing',
                    'text-dx': 'dx',
                    'text-dy': 'dy',
                    'text-face-name': 'face_name',
                    'text-fill': 'fill',
                    'text-fontset': 'fontset',
                    'text-halo-fill': 'halo_fill',
                    'text-halo-radius': 'halo_radius',
                    'text-justify-align': 'justify_alignment',
                    'text-label-position-tolerance': 'label_position_tolerance',
                    'text-line-spacing': 'line_spacing',
                    'text-max-char-angle-delta': 'max_char_angle_delta',
                    'text-min-distance': 'minimum_distance',
                    'text-placement': 'label_placement',
                    'text-ratio': 'text_ratio',
                    'text-size': 'size', 
                    'text-spacing': 'spacing',
                    'text-transform': 'text_convert',
                    'text-vertical-align': 'vertical_alignment',
                    'text-wrap-width': 'wrap_width',
                    'text-meta-output': 'meta-output',
                    'text-meta-writer': 'meta-writer'
                    }

    property_names = property_map.keys()
    
    # pull out all the names
    text_names = [dec.selector.elements[1].names[0]
                  for dec in declarations
                  if len(dec.selector.elements) is 2 and len(dec.selector.elements[1].names) is 1]
    
    # a place to put groups
    groups = []
    
    # a separate style element for each text name
    for text_name in set(text_names):
    
        # just the ones we care about here.
        # the complicated conditional means: get all declarations that
        # apply to this text_name specifically, or text in general.
        name_declarations = [dec for dec in declarations
                             if dec.property.name in property_map
                                and (len(dec.selector.elements) == 1
                                     or (len(dec.selector.elements) == 2
                                         and dec.selector.elements[1].names[0] in (text_name, '*')))]
        
        # a place to put rules
        rules = []
        
        for (filter, values) in filtered_property_declarations(name_declarations, property_names):
            
            face_name = values.has_key('text-face-name') and values['text-face-name'].value or None
            fontset = values.has_key('text-fontset') and values['text-fontset'].value or None
            size = values.has_key('text-size') and values['text-size'].value
            color = values.has_key('text-fill') and values['text-fill'].value
            
            ratio = values.has_key('text-ratio') and values['text-ratio'].value or None
            wrap_width = values.has_key('text-wrap-width') and values['text-wrap-width'].value or None
            label_spacing = values.has_key('text-spacing') and values['text-spacing'].value or None
            label_position_tolerance = values.has_key('text-label-position-tolerance') and values['text-label-position-tolerance'].value or None
            max_char_angle_delta = values.has_key('text-max-char-angle-delta') and values['text-max-char-angle-delta'].value or None
            halo_color = values.has_key('text-halo-fill') and values['text-halo-fill'].value or None
            halo_radius = values.has_key('text-halo-radius') and values['text-halo-radius'].value or None
            dx = values.has_key('text-dx') and values['text-dx'].value or None
            dy = values.has_key('text-dy') and values['text-dy'].value or None
            avoid_edges = values.has_key('text-avoid-edges') and values['text-avoid-edges'].value or None
            minimum_distance = values.has_key('text-min-distance') and values['text-min-distance'].value or None
            allow_overlap = values.has_key('text-allow-overlap') and values['text-allow-overlap'].value or None
            label_placement = values.has_key('text-placement') and values['text-placement'].value or None
            text_transform = values.has_key('text-transform') and values['text-transform'].value or None
            anchor_dx = values.has_key('text-anchor-dx') and values['text-anchor-dx'].value or None
            anchor_dy = values.has_key('text-anchor-dy') and values['text-anchor-dy'].value or None
            horizontal_alignment = values.has_key('text-horizontal-align') and values['text-horizontal-align'].value or None
            vertical_alignment = values.has_key('text-vertical-align') and values['text-vertical-align'].value or None
            justify_alignment = values.has_key('text-justify-align') and values['text-justify-align'].value or None
            line_spacing = values.has_key('text-line-spacing') and values['text-line-spacing'].value or None
            character_spacing = values.has_key('text-character-spacing') and values['text-character-spacing'].value or None
            
            if (face_name or fontset) and size and color:
                symbolizer = output.TextSymbolizer(text_name, face_name, size, color, \
                                              wrap_width, label_spacing, label_position_tolerance, \
                                              max_char_angle_delta, halo_color, halo_radius, dx, dy, \
                                              avoid_edges, minimum_distance, allow_overlap, label_placement, \
                                              line_spacing, character_spacing, text_transform, fontset,
                                              anchor_dx, anchor_dy,horizontal_alignment, \
                                              vertical_alignment, justify_alignment)
            
                rules.append(make_rule(filter, symbolizer))
        
        groups.append((text_name, rules))
    
    return dict(groups)