def test_parse_dxfs():
    reference_file = os.path.join(DATADIR, 'reader',
                                  'conditional-formatting.xlsx')
    wb = load_workbook(reference_file)
    archive = ZipFile(reference_file, 'r', ZIP_DEFLATED)
    read_xml = archive.read(ARC_STYLE)

    # Verify length
    assert '<dxfs count="164">' in str(read_xml)
    assert len(wb.style_properties['dxf_list']) == 164

    # Verify first dxf style
    reference_file = os.path.join(DATADIR, 'writer', 'expected',
                                  'dxf_style.xml')
    with open(reference_file) as expected:
        diff = compare_xml(read_xml, expected.read())
        assert diff is None, diff

    cond_styles = wb.style_properties['dxf_list'][0]
    assert cond_styles['font']['color'] == Color('FF9C0006')
    assert cond_styles['font']['bold'] == False
    assert cond_styles['font']['italic'] == False
    f = Fill()
    f.end_color = Color('FFFFC7CE')
    assert cond_styles['fill'][0] == f

    # Verify that the dxf styles stay the same when they're written and read back in.
    w = StyleWriter(wb)
    w._write_dxfs()
    write_xml = get_xml(w._root)
    read_style_prop = read_style_table(write_xml)
    assert len(read_style_prop['dxf_list']) == len(
        wb.style_properties['dxf_list'])
    for i, dxf in enumerate(read_style_prop['dxf_list']):
        assert repr(wb.style_properties['dxf_list'][i] == dxf)
예제 #2
0
    def point(self, pt, fill):
        color = "00%02X%02X%02X" % fill

        cell = self.sheet.cell(column=pt[0], row=pt[1])
        cell.style.fill.fill_type = Fill.FILL_SOLID
        cell.style.fill.start_color = Color(color)
        cell.style.fill.end_color = Color(color)
    def test_conditional_formatting_setRules(self):
        class WS():
            conditional_formatting = ConditionalFormatting()

        worksheet = WS()
        rules = {
            'A1:A4': [{
                'type': 'colorScale',
                'priority': '13',
                'colorScale': {
                    'cfvo': [{
                        'type': 'min'
                    }, {
                        'type': 'max'
                    }],
                    'color': [Color('FFFF7128'),
                              Color('FFFFEF9C')]
                }
            }]
        }
        worksheet.conditional_formatting.setRules(rules)

        temp_buffer = StringIO()
        doc = XMLGenerator(out=temp_buffer, encoding='utf-8')
        write_worksheet_conditional_formatting(doc, worksheet)
        doc.endDocument()
        xml = temp_buffer.getvalue()
        temp_buffer.close()

        expected = '<conditionalFormatting sqref="A1:A4"><cfRule type="colorScale" priority="1"><colorScale><cfvo type="min"></cfvo><cfvo type="max"></cfvo><color rgb="FFFF7128"></color><color rgb="FFFFEF9C"></color></colorScale></cfRule></conditionalFormatting>'
        diff = compare_xml(xml, expected)
        assert diff is None, diff
예제 #4
0
def parse_dxfs(root, color_index):
    """Read in the dxfs effects - used by conditional formatting."""
    dxf_list = []
    dxfs = root.find('{%s}dxfs' % SHEET_MAIN_NS)
    if dxfs is not None:
        nodes = dxfs.findall('{%s}dxf' % SHEET_MAIN_NS)
        for dxf in nodes:
            dxf_item = {}
            font_node = dxf.find('{%s}font' % SHEET_MAIN_NS)
            if font_node is not None:
                dxf_item['font'] = {}
                dxf_item['font']['bold'] = True if len(font_node.findall('{%s}b' % SHEET_MAIN_NS)) else False
                dxf_item['font']['italic'] = True if len(font_node.findall('{%s}i' % SHEET_MAIN_NS)) else False
                if len(font_node.findall('{%s}u' % SHEET_MAIN_NS)):
                    underline = font_node.find('{%s}u' % SHEET_MAIN_NS).get('val')
                    dxf_item['font']['underline'] = underline if underline else 'single'
                color = font_node.find('{%s}color' % SHEET_MAIN_NS)
                if color is not None:
                    dxf_item['font']['color'] = Color(Color.BLACK)
                    if color.get('indexed') is not None and 0 <= int(color.get('indexed')) < len(color_index):
                        dxf_item['font']['color'].index = color_index[int(color.get('indexed'))]
                    elif color.get('theme') is not None:
                        if color.get('tint') is not None:
                            dxf_item['font']['color'] .index = 'theme:%s:%s' % (color.get('theme'), color.get('tint'))
                        else:
                            dxf_item['font']['color'] .index = 'theme:%s:' % color.get('theme') # prefix color with theme
                    elif color.get('rgb'):
                        dxf_item['font']['color'] .index = color.get('rgb')
            fill_node = dxf.find('{%s}fill' % SHEET_MAIN_NS)
            if fill_node is not None:
                dxf_item['fill'] = parse_fills(dxf, color_index, True)
                dxf_item['border'] = parse_borders(dxf, color_index, True)
            dxf_list.append(dxf_item)
    return dxf_list
예제 #5
0
 def __init__(self):
     self.visible = False
     self.blurRadius = 6
     self.distance = 2
     self.direction = 0
     self.alignment = self.SHADOW_BOTTOM_RIGHT
     self.color = Color(Color.BLACK)
     self.alpha = 50
예제 #6
0
def parse_dxfs(root, color_index):
    """Read in the dxfs effects - used by conditional formatting."""
    dxf_list = []
    dxfs = root.find("{%s}dxfs" % SHEET_MAIN_NS)
    if dxfs is not None:
        nodes = dxfs.findall("{%s}dxf" % SHEET_MAIN_NS)
        for dxf in nodes:
            dxf_item = {}
            font_node = dxf.find("{%s}font" % SHEET_MAIN_NS)
            if font_node is not None:
                dxf_item["font"] = {}
                dxf_item["font"]["bold"] = True if len(font_node.findall("{%s}b" % SHEET_MAIN_NS)) else False
                dxf_item["font"]["italic"] = True if len(font_node.findall("{%s}i" % SHEET_MAIN_NS)) else False
                if len(font_node.findall("{%s}u" % SHEET_MAIN_NS)):
                    underline = font_node.find("{%s}u" % SHEET_MAIN_NS).get("val")
                    dxf_item["font"]["underline"] = underline if underline else "single"
                color = font_node.find("{%s}color" % SHEET_MAIN_NS)
                if color is not None:
                    dxf_item["font"]["color"] = Color(Color.BLACK)
                    if color.get("indexed") is not None and 0 <= int(color.get("indexed")) < len(color_index):
                        dxf_item["font"]["color"].index = color_index[int(color.get("indexed"))]
                    elif color.get("theme") is not None:
                        if color.get("tint") is not None:
                            dxf_item["font"]["color"].index = "theme:%s:%s" % (color.get("theme"), color.get("tint"))
                        else:
                            dxf_item["font"]["color"].index = "theme:%s:" % color.get(
                                "theme"
                            )  # prefix color with theme
                    elif color.get("rgb"):
                        dxf_item["font"]["color"].index = color.get("rgb")
            fill_node = dxf.find("{%s}fill" % SHEET_MAIN_NS)
            if fill_node is not None:
                dxf_item["fill"] = parse_fills(dxf, color_index, True)
                dxf_item["border"] = parse_borders(dxf, color_index, True)
            dxf_list.append(dxf_item)
    return dxf_list
예제 #7
0
def parse_dxfs(root, color_index):
    """Read in the dxfs effects - used by conditional formatting."""
    dxf_list = []
    dxfs = root.find('{%s}dxfs' % SHEET_MAIN_NS)
    if dxfs is not None:
        nodes = dxfs.findall('{%s}dxf' % SHEET_MAIN_NS)
        for dxf in nodes:
            dxf_item = {}
            font_node = dxf.find('{%s}font' % SHEET_MAIN_NS)
            if font_node is not None:
                dxf_item['font'] = {}
                dxf_item['font']['bold'] = True if len(
                    font_node.findall('{%s}b' % SHEET_MAIN_NS)) else False
                dxf_item['font']['italic'] = True if len(
                    font_node.findall('{%s}i' % SHEET_MAIN_NS)) else False
                if len(font_node.findall('{%s}u' % SHEET_MAIN_NS)):
                    underline = font_node.find('{%s}u' %
                                               SHEET_MAIN_NS).get('val')
                    dxf_item['font'][
                        'underline'] = underline if underline else 'single'
                color = font_node.find('{%s}color' % SHEET_MAIN_NS)
                if color is not None:
                    dxf_item['font']['color'] = Color(Color.BLACK)
                    if color.get('indexed') is not None and 0 <= int(
                            color.get('indexed')) < len(color_index):
                        dxf_item['font']['color'].index = color_index[int(
                            color.get('indexed'))]
                    elif color.get('theme') is not None:
                        if color.get('tint') is not None:
                            dxf_item['font']['color'].index = 'theme:%s:%s' % (
                                color.get('theme'), color.get('tint'))
                        else:
                            dxf_item['font'][
                                'color'].index = 'theme:%s:' % color.get(
                                    'theme')  # prefix color with theme
                    elif color.get('rgb'):
                        dxf_item['font']['color'].index = color.get('rgb')
            fill_node = dxf.find('{%s}fill' % SHEET_MAIN_NS)
            if fill_node is not None:
                dxf_item['fill'] = parse_fills(dxf, color_index, True)
                dxf_item['border'] = parse_borders(dxf, color_index, True)
            dxf_list.append(dxf_item)
    return dxf_list
예제 #8
0
    def parser_conditional_formatting(self, element):
        rules = {}
        for cf in safe_iterator(element, '{%s}conditionalFormatting' % SHEET_MAIN_NS):
            if not cf.get('sqref'):
                # Potentially flag - this attribute should always be present.
                continue
            range_string = cf.get('sqref')
            cfRules = cf.findall('{%s}cfRule' % SHEET_MAIN_NS)
            rules[range_string] = []
            for cfRule in cfRules:
                if not cfRule.get('type') or cfRule.get('type') == 'dataBar':
                    # dataBar conditional formatting isn't supported, as it relies on the complex <extLst> tag
                    continue
                rule = {'type': cfRule.get('type')}
                for attr in ConditionalFormatting.rule_attributes:
                    if cfRule.get(attr) is not None:
                        rule[attr] = cfRule.get(attr)

                formula = cfRule.findall('{%s}formula' % SHEET_MAIN_NS)
                for f in formula:
                    if 'formula' not in rule:
                        rule['formula'] = []
                    rule['formula'].append(f.text)

                colorScale = cfRule.find('{%s}colorScale' % SHEET_MAIN_NS)
                if colorScale is not None:
                    rule['colorScale'] = {'cfvo': [], 'color': []}
                    cfvoNodes = colorScale.findall('{%s}cfvo' % SHEET_MAIN_NS)
                    for node in cfvoNodes:
                        cfvo = {}
                        if node.get('type') is not None:
                            cfvo['type'] = node.get('type')
                        if node.get('val') is not None:
                            cfvo['val'] = node.get('val')
                        rule['colorScale']['cfvo'].append(cfvo)
                    colorNodes = colorScale.findall('{%s}color' % SHEET_MAIN_NS)
                    for color in colorNodes:
                        c = Color(Color.BLACK)
                        if self.color_index\
                           and color.get('indexed') is not None\
                           and 0 <= int(color.get('indexed')) < len(self.color_index):
                            c.index = self.color_index[int(color.get('indexed'))]
                        if color.get('theme') is not None:
                            if color.get('tint') is not None:
                                c.index = 'theme:%s:%s' % (color.get('theme'), color.get('tint'))
                            else:
                                c.index = 'theme:%s:' % color.get('theme')  # prefix color with theme
                        elif color.get('rgb'):
                            c.index = color.get('rgb')
                        rule['colorScale']['color'].append(c)

                iconSet = cfRule.find('{%s}iconSet' % SHEET_MAIN_NS)
                if iconSet is not None:
                    rule['iconSet'] = {'cfvo': []}
                    for iconAttr in ConditionalFormatting.icon_attributes:
                        if iconSet.get(iconAttr) is not None:
                            rule['iconSet'][iconAttr] = iconSet.get(iconAttr)
                    cfvoNodes = iconSet.findall('{%s}cfvo' % SHEET_MAIN_NS)
                    for node in cfvoNodes:
                        cfvo = {}
                        if node.get('type') is not None:
                            cfvo['type'] = node.get('type')
                        if node.get('val') is not None:
                            cfvo['val'] = node.get('val')
                        rule['iconSet']['cfvo'].append(cfvo)

                rules[range_string].append(rule)
        if len(rules):
            self.ws.conditional_formatting.setRules(rules)
예제 #9
0
    def parser_conditional_formatting(self, element):
        rules = {}
        for cf in safe_iterator(element, "{%s}conditionalFormatting" % SHEET_MAIN_NS):
            if not cf.get("sqref"):
                # Potentially flag - this attribute should always be present.
                continue
            range_string = cf.get("sqref")
            cfRules = cf.findall("{%s}cfRule" % SHEET_MAIN_NS)
            rules[range_string] = []
            for cfRule in cfRules:
                if not cfRule.get("type") or cfRule.get("type") == "dataBar":
                    # dataBar conditional formatting isn't supported, as it relies on the complex <extLst> tag
                    continue
                rule = {"type": cfRule.get("type")}
                for attr in ConditionalFormatting.rule_attributes:
                    if cfRule.get(attr) is not None:
                        rule[attr] = cfRule.get(attr)

                formula = cfRule.findall("{%s}formula" % SHEET_MAIN_NS)
                for f in formula:
                    if "formula" not in rule:
                        rule["formula"] = []
                    rule["formula"].append(f.text)

                colorScale = cfRule.find("{%s}colorScale" % SHEET_MAIN_NS)
                if colorScale is not None:
                    rule["colorScale"] = {"cfvo": [], "color": []}
                    cfvoNodes = colorScale.findall("{%s}cfvo" % SHEET_MAIN_NS)
                    for node in cfvoNodes:
                        cfvo = {}
                        if node.get("type") is not None:
                            cfvo["type"] = node.get("type")
                        if node.get("val") is not None:
                            cfvo["val"] = node.get("val")
                        rule["colorScale"]["cfvo"].append(cfvo)
                    colorNodes = colorScale.findall("{%s}color" % SHEET_MAIN_NS)
                    for color in colorNodes:
                        c = Color(Color.BLACK)
                        if (
                            self.color_index
                            and color.get("indexed") is not None
                            and 0 <= int(color.get("indexed")) < len(self.color_index)
                        ):
                            c.index = self.color_index[int(color.get("indexed"))]
                        if color.get("theme") is not None:
                            if color.get("tint") is not None:
                                c.index = "theme:%s:%s" % (color.get("theme"), color.get("tint"))
                            else:
                                c.index = "theme:%s:" % color.get("theme")  # prefix color with theme
                        elif color.get("rgb"):
                            c.index = color.get("rgb")
                        rule["colorScale"]["color"].append(c)

                iconSet = cfRule.find("{%s}iconSet" % SHEET_MAIN_NS)
                if iconSet is not None:
                    rule["iconSet"] = {"cfvo": []}
                    for iconAttr in ConditionalFormatting.icon_attributes:
                        if iconSet.get(iconAttr) is not None:
                            rule["iconSet"][iconAttr] = iconSet.get(iconAttr)
                    cfvoNodes = iconSet.findall("{%s}cfvo" % SHEET_MAIN_NS)
                    for node in cfvoNodes:
                        cfvo = {}
                        if node.get("type") is not None:
                            cfvo["type"] = node.get("type")
                        if node.get("val") is not None:
                            cfvo["val"] = node.get("val")
                        rule["iconSet"]["cfvo"].append(cfvo)

                rules[range_string].append(rule)
        if len(rules):
            self.ws.conditional_formatting.setRules(rules)
예제 #10
0
    def parser_conditional_formatting(self, element):
        rules = {}
        for cf in safe_iterator(element, '{%s}conditionalFormatting' % SHEET_MAIN_NS):
            if not cf.get('sqref'):
                # Potentially flag - this attribute should always be present.
                continue
            range_string = cf.get('sqref')
            cfRules = cf.findall('{%s}cfRule' % SHEET_MAIN_NS)
            rules[range_string] = []
            for cfRule in cfRules:
                if not cfRule.get('type') or cfRule.get('type') == 'dataBar':
                    # dataBar conditional formatting isn't supported, as it relies on the complex <extLst> tag
                    continue
                rule = {'type': cfRule.get('type')}
                for attr in ConditionalFormatting.rule_attributes:
                    if cfRule.get(attr) is not None:
                        rule[attr] = cfRule.get(attr)

                formula = cfRule.findall('{%s}formula' % SHEET_MAIN_NS)
                for f in formula:
                    if 'formula' not in rule:
                        rule['formula'] = []
                    rule['formula'].append(f.text)

                colorScale = cfRule.find('{%s}colorScale' % SHEET_MAIN_NS)
                if colorScale is not None:
                    rule['colorScale'] = {'cfvo': [], 'color': []}
                    cfvoNodes = colorScale.findall('{%s}cfvo' % SHEET_MAIN_NS)
                    for node in cfvoNodes:
                        cfvo = {}
                        if node.get('type') is not None:
                            cfvo['type'] = node.get('type')
                        if node.get('val') is not None:
                            cfvo['val'] = node.get('val')
                        rule['colorScale']['cfvo'].append(cfvo)
                    colorNodes = colorScale.findall('{%s}color' % SHEET_MAIN_NS)
                    for color in colorNodes:
                        c = Color(Color.BLACK)
                        if self.color_index\
                           and color.get('indexed') is not None\
                           and 0 <= int(color.get('indexed')) < len(color_index):
                            c.index = color_index[int(color.get('indexed'))]
                        if color.get('theme') is not None:
                            if color.get('tint') is not None:
                                c.index = 'theme:%s:%s' % (color.get('theme'), color.get('tint'))
                            else:
                                c.index = 'theme:%s:' % color.get('theme')  # prefix color with theme
                        elif color.get('rgb'):
                            c.index = color.get('rgb')
                        rule['colorScale']['color'].append(c)

                iconSet = cfRule.find('{%s}iconSet' % SHEET_MAIN_NS)
                if iconSet is not None:
                    rule['iconSet'] = {'cfvo': []}
                    for iconAttr in ConditionalFormatting.icon_attributes:
                        if iconSet.get(iconAttr) is not None:
                            rule['iconSet'][iconAttr] = iconSet.get(iconAttr)
                    cfvoNodes = iconSet.findall('{%s}cfvo' % SHEET_MAIN_NS)
                    for node in cfvoNodes:
                        cfvo = {}
                        if node.get('type') is not None:
                            cfvo['type'] = node.get('type')
                        if node.get('val') is not None:
                            cfvo['val'] = node.get('val')
                        rule['iconSet']['cfvo'].append(cfvo)

                rules[range_string].append(rule)
        if len(rules):
            self.ws.conditional_formatting.setRules(rules)
예제 #11
0
def fast_parse(ws, xml_source, string_table, style_table, color_index=None):

    root = fromstring(xml_source)
    guess_types = ws.parent._guess_types

    mergeCells = root.find('{%s}mergeCells' % SHEET_MAIN_NS)
    if mergeCells is not None:
        for mergeCell in mergeCells.findall('{%s}mergeCell' % SHEET_MAIN_NS):
            ws.merge_cells(mergeCell.get('ref'))

    source = _get_xml_iter(xml_source)

    it = iterparse(source)

    for event, element in filter(filter_cells, it):

        value = element.findtext('{%s}v' % SHEET_MAIN_NS)
        formula = element.find('{%s}f' % SHEET_MAIN_NS)

        coordinate = element.get('r')
        style_id = element.get('s')
        if style_id is not None:
            ws._styles[coordinate] = style_table.get(int(style_id))

        if value is not None:
            data_type = element.get('t', 'n')
            if data_type == Cell.TYPE_STRING:
                value = string_table.get(int(value))
            if formula is not None:
                if formula.text:
                    value = "=" + str(formula.text)
                else:
                    value = "="
                formula_type = formula.get('t')
                if formula_type:
                    ws.formula_attributes[coordinate] = {'t': formula_type}
                    if formula.get('si'):  # Shared group index for shared formulas
                        ws.formula_attributes[coordinate]['si'] = formula.get('si')
                    if formula.get('ref'):  # Range for shared formulas
                        ws.formula_attributes[coordinate]['ref'] = formula.get('ref')
            if not guess_types and formula is None:
                ws.cell(coordinate).set_explicit_value(value=value, data_type=data_type)
            else:
                ws.cell(coordinate).value = value

        # to avoid memory exhaustion, clear the item after use
        element.clear()

    cols = root.find('{%s}cols' % SHEET_MAIN_NS)
    if cols is not None:
        colNodes = cols.findall('{%s}col' % SHEET_MAIN_NS)
        for col in colNodes:
            min = int(col.get('min')) if col.get('min') else 1
            max = int(col.get('max')) if col.get('max') else 1
            # Ignore ranges that go up to the max column 16384.  Columns need to be extended to handle
            # ranges without creating an entry for every single one.
            if max != 16384:
                for colId in range(min, max + 1):
                    column = get_column_letter(colId)
                    if column not in ws.column_dimensions:
                        ws.column_dimensions[column] = ColumnDimension(column)
                    if col.get('width') is not None:
                        ws.column_dimensions[column].width = float(col.get('width'))
                    if col.get('bestFit') == '1':
                        ws.column_dimensions[column].auto_size = True
                    if col.get('hidden') == '1':
                        ws.column_dimensions[column].visible = False
                    if col.get('outlineLevel') is not None:
                        ws.column_dimensions[column].outline_level = int(col.get('outlineLevel'))
                    if col.get('collapsed') == '1':
                        ws.column_dimensions[column].collapsed = True
                    if col.get('style') is not None:
                        ws.column_dimensions[column].style_index = style_table.get(int(col.get('style')))

    sheetData = root.find('{%s}sheetData' % SHEET_MAIN_NS)
    if sheetData is not None:
        rowNodes = sheetData.findall('{%s}row' % SHEET_MAIN_NS)
        for row in rowNodes:
            rowId = int(row.get('r'))
            if rowId not in ws.row_dimensions:
                ws.row_dimensions[rowId] = RowDimension(rowId)
            if row.get('ht') is not None:
                ws.row_dimensions[rowId].height = float(row.get('ht'))

    printOptions = root.find('{%s}printOptions' % SHEET_MAIN_NS)
    if printOptions is not None:
        if printOptions.get('horizontalCentered') is not None:
            ws.page_setup.horizontalCentered = printOptions.get('horizontalCentered')
        if printOptions.get('verticalCentered') is not None:
            ws.page_setup.verticalCentered = printOptions.get('verticalCentered')

    pageMargins = root.find('{%s}pageMargins' % SHEET_MAIN_NS)
    if pageMargins is not None:
        if pageMargins.get('left') is not None:
            ws.page_margins.left = float(pageMargins.get('left'))
        if pageMargins.get('right') is not None:
            ws.page_margins.right = float(pageMargins.get('right'))
        if pageMargins.get('top') is not None:
            ws.page_margins.top = float(pageMargins.get('top'))
        if pageMargins.get('bottom') is not None:
            ws.page_margins.bottom = float(pageMargins.get('bottom'))
        if pageMargins.get('header') is not None:
            ws.page_margins.header = float(pageMargins.get('header'))
        if pageMargins.get('footer') is not None:
            ws.page_margins.footer = float(pageMargins.get('footer'))

    pageSetup = root.find('{%s}pageSetup' % SHEET_MAIN_NS)
    if pageSetup is not None:
        if pageSetup.get('orientation') is not None:
            ws.page_setup.orientation = pageSetup.get('orientation')
        if pageSetup.get('paperSize') is not None:
            ws.page_setup.paperSize = pageSetup.get('paperSize')
        if pageSetup.get('scale') is not None:
            ws.page_setup.top = pageSetup.get('scale')
        if pageSetup.get('fitToPage') is not None:
            ws.page_setup.fitToPage = pageSetup.get('fitToPage')
        if pageSetup.get('fitToHeight') is not None:
            ws.page_setup.fitToHeight = pageSetup.get('fitToHeight')
        if pageSetup.get('fitToWidth') is not None:
            ws.page_setup.fitToWidth = pageSetup.get('fitToWidth')
        if pageSetup.get('firstPageNumber') is not None:
            ws.page_setup.firstPageNumber = pageSetup.get('firstPageNumber')
        if pageSetup.get('useFirstPageNumber') is not None:
            ws.page_setup.useFirstPageNumber = pageSetup.get('useFirstPageNumber')

    headerFooter = root.find('{%s}headerFooter' % SHEET_MAIN_NS)
    if headerFooter is not None:
        oddHeader = headerFooter.find('{%s}oddHeader' % SHEET_MAIN_NS)
        if oddHeader is not None and oddHeader.text is not None:
            ws.header_footer.setHeader(oddHeader.text)
        oddFooter = headerFooter.find('{%s}oddFooter' % SHEET_MAIN_NS)
        if oddFooter is not None and oddFooter.text is not None:
            ws.header_footer.setFooter(oddFooter.text)

    conditionalFormattingNodes = root.findall('{%s}conditionalFormatting' % SHEET_MAIN_NS)
    rules = {}
    for cf in conditionalFormattingNodes:
        if not cf.get('sqref'):
            # Potentially flag - this attribute should always be present.
            continue
        range_string = cf.get('sqref')
        cfRules = cf.findall('{%s}cfRule' % SHEET_MAIN_NS)
        rules[range_string] = []
        for cfRule in cfRules:
            if not cfRule.get('type') or cfRule.get('type') == 'dataBar':
                # dataBar conditional formatting isn't supported, as it relies on the complex <extLst> tag
                continue
            rule = {'type': cfRule.get('type')}
            for attr in ConditionalFormatting.rule_attributes:
                if cfRule.get(attr) is not None:
                    rule[attr] = cfRule.get(attr)

            formula = cfRule.findall('{%s}formula' % SHEET_MAIN_NS)
            for f in formula:
                if 'formula' not in rule:
                    rule['formula'] = []
                rule['formula'].append(f.text)

            colorScale = cfRule.find('{%s}colorScale' % SHEET_MAIN_NS)
            if colorScale is not None:
                rule['colorScale'] = {'cfvo': [], 'color': []}
                cfvoNodes = colorScale.findall('{%s}cfvo' % SHEET_MAIN_NS)
                for node in cfvoNodes:
                    cfvo = {}
                    if node.get('type') is not None:
                        cfvo['type'] = node.get('type')
                    if node.get('val') is not None:
                        cfvo['val'] = node.get('val')
                    rule['colorScale']['cfvo'].append(cfvo)
                colorNodes = colorScale.findall('{%s}color' % SHEET_MAIN_NS)
                for color in colorNodes:
                    c = Color(Color.BLACK)
                    if color_index and color.get('indexed') is not None and 0 <= int(color.get('indexed')) < len(color_index):
                        c.index = color_index[int(color.get('indexed'))]
                    if color.get('theme') is not None:
                        if color.get('tint') is not None:
                            c.index = 'theme:%s:%s' % (color.get('theme'), color.get('tint'))
                        else:
                            c.index = 'theme:%s:' % color.get('theme')  # prefix color with theme
                    elif color.get('rgb'):
                        c.index = color.get('rgb')
                    rule['colorScale']['color'].append(c)

            iconSet = cfRule.find('{%s}iconSet' % SHEET_MAIN_NS)
            if iconSet is not None:
                rule['iconSet'] = {'cfvo': []}
                for iconAttr in ConditionalFormatting.icon_attributes:
                    if iconSet.get(iconAttr) is not None:
                        rule['iconSet'][iconAttr] = iconSet.get(iconAttr)
                cfvoNodes = iconSet.findall('{%s}cfvo' % SHEET_MAIN_NS)
                for node in cfvoNodes:
                    cfvo = {}
                    if node.get('type') is not None:
                        cfvo['type'] = node.get('type')
                    if node.get('val') is not None:
                        cfvo['val'] = node.get('val')
                    rule['iconSet']['cfvo'].append(cfvo)

            rules[range_string].append(rule)
    if len(rules):
        ws.conditional_formatting.setRules(rules)