1
#!/usr/bin/env Python
2
"""
3
Tables Extension for Python-Markdown
4
====================================
5
6
Added parsing of tables to Python-Markdown.
7
8
A simple example:
9
10
    First Header  | Second Header
11
    ------------- | -------------
12
    Content Cell  | Content Cell
13
    Content Cell  | Content Cell
14
15
Copyright 2009 - [Waylan Limberg](http://achinghead.com)
16
"""
17
import markdown
18
from markdown.util import etree
19
20
21
class TableProcessor(markdown.blockprocessors.BlockProcessor):
22
    """ Process Tables. """
23
24
    def test(self, parent, block):
25
        rows = block.split('\n')
26
        return (len(rows) > 2 and '|' in rows[0] and 
27
                '|' in rows[1] and '-' in rows[1] and 
28
                rows[1][0] in ['|', ':', '-'])
29
30
    def run(self, parent, blocks):
31
        """ Parse a table block and build table. """
32
        block = blocks.pop(0).split('\n')
33
        header = block[:2]
34
        rows = block[2:]
35
        # Get format type (bordered by pipes or not)
36
        border = False
37
        if header[0].startswith('|'):
38
            border = True
39
        # Get alignment of columns
40
        align = []
41
        for c in self._split_row(header[1], border):
42
            if c.startswith(':') and c.endswith(':'):
43
                align.append('center')
44
            elif c.startswith(':'):
45
                align.append('left')
46
            elif c.endswith(':'):
47
                align.append('right')
48
            else:
49
                align.append(None)
50
        # Build table
51
        table = etree.SubElement(parent, 'table')
52
        thead = etree.SubElement(table, 'thead')
53
        self._build_row(header[0], thead, align, border)
54
        tbody = etree.SubElement(table, 'tbody')
55
        for row in rows:
56
            self._build_row(row, tbody, align, border)
57
58
    def _build_row(self, row, parent, align, border):
59
        """ Given a row of text, build table cells. """
60
        tr = etree.SubElement(parent, 'tr')
61
        tag = 'td'
62
        if parent.tag == 'thead':
63
            tag = 'th'
64
        cells = self._split_row(row, border)
65
        # We use align here rather than cells to ensure every row 
66
        # contains the same number of columns.
67
        for i, a in enumerate(align):
68
            c = etree.SubElement(tr, tag)
69
            try:
70
                c.text = cells[i].strip()
71
            except IndexError:
72
                c.text = ""
73
            if a:
74
                c.set('align', a)
75
76
    def _split_row(self, row, border):
77
        """ split a row of text into list of cells. """
78
        if border:
79
            if row.startswith('|'):
80
                row = row[1:]
81
            if row.endswith('|'):
82
                row = row[:-1]
83
        return row.split('|')
84
85
86
class TableExtension(markdown.Extension):
87
    """ Add tables to Markdown. """
88
89
    def extendMarkdown(self, md, md_globals):
90
        """ Add an instance of TableProcessor to BlockParser. """
91
        md.parser.blockprocessors.add('table', 
92
                                      TableProcessor(md.parser),
93
                                      '<hashheader')
94
95
96
def makeExtension(configs={}):
97
    return TableExtension(configs=configs)